From 6540ddc24ba65fdf4863c78b0119869f8dfd0ed8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 15 Sep 2019 19:30:42 -0600 Subject: [PATCH 001/166] Fix bis key generation for newer hardware --- source/keys/key_sources.inl | 22 ++++++++++++++++++++++ source/keys/keys.c | 25 +++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index df366a2..02a13d7 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -68,6 +68,28 @@ static const u8 master_key_source[0x10] = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; static const u8 per_console_key_source[0x10] = { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; +static const u8 per_console_key_source_4x[0x10] = { + 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; + +static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ + {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ + {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ +}; + +static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ + {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ + {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ + {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */ +}; // from SPL static const u8 aes_key_generation_source[0x10] = { diff --git a/source/keys/keys.c b/source/keys/keys.c index fd5a42e..9f3a135 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -61,6 +61,7 @@ emmc_part_t *system_part; static u8 temp_key[0x10], bis_key[4][0x20] = {0}, device_key[0x10] = {0}, + new_device_key[0x10] = {0}, sd_seed[0x10] = {0}, // FS-related keys fs_keys[10][0x20] = {0}, @@ -260,8 +261,10 @@ get_tsec: ; se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keyblob_key[i], 0x10); se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) - if (i == 0) + if (i == 0) { se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) + se_aes_crypt_block_ecb(7, 0, new_device_key, per_console_key_source_4x); + } // verify keyblob is not corrupt sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); @@ -290,14 +293,28 @@ get_tsec: ; /* key = unwrap(source, wrapped_key): key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key */ - // TODO: fix bis key generation for newer unpatched consoles + + u32 key_generation = 0; + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { + if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { + key_generation = fuse_read_odm(2) & 0x1F; + } + } if (_key_exists(device_key)) { - se_aes_key_set(8, device_key, 0x10); + if (key_generation) { + se_aes_key_set(8, new_device_key, 0x10); + se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); + se_aes_key_set(8, master_key[0], 0x10); + se_aes_unwrap_key(8, 8, new_device_keygen_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); + se_aes_crypt_block_ecb(8, 0, temp_key, temp_key); + } else + memcpy(temp_key, device_key, 0x10); + se_aes_key_set(8, temp_key, 0x10); se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source); + _generate_kek(8, bis_kek_source, temp_key, aes_kek_generation_source, aes_key_generation_source); se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); From 19796e486c3002647cccf0a9b1528389256b5599 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 16 Sep 2019 22:18:41 -0600 Subject: [PATCH 002/166] Add hekate cfg and color incrementing --- source/config/config.c | 668 +++++++++++++++++++++++++++++++++++++++++ source/config/config.h | 57 ++++ source/config/ini.c | 193 ++++++++++++ source/config/ini.h | 50 +++ source/keys/keys.c | 61 ++-- source/main.c | 4 + source/utils/dirlist.c | 94 ++++++ source/utils/dirlist.h | 19 ++ 8 files changed, 1122 insertions(+), 24 deletions(-) create mode 100644 source/config/config.c create mode 100644 source/config/config.h create mode 100644 source/config/ini.c create mode 100644 source/config/ini.h create mode 100644 source/utils/dirlist.c create mode 100644 source/utils/dirlist.h diff --git a/source/config/config.c b/source/config/config.c new file mode 100644 index 0000000..f9df696 --- /dev/null +++ b/source/config/config.c @@ -0,0 +1,668 @@ +/* + * 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 . + */ + +#include +#include + +#include "config.h" +#include "ini.h" +#include "../gfx/gfx.h" +#include "../gfx/tui.h" +#include "../libs/fatfs/ff.h" +#include "../soc/t210.h" +#include "../storage/sdmmc.h" +#include "../utils/btn.h" +#include "../utils/list.h" +#include "../utils/util.h" + +extern hekate_config h_cfg; +extern bool sd_mount(); +extern void sd_unmount(); + +void set_default_configuration() +{ + h_cfg.autoboot = 0; + h_cfg.autoboot_list = 0; + h_cfg.bootwait = 3; + h_cfg.verification = 1; + h_cfg.se_keygen_done = 0; + h_cfg.sbar_time_keeping = 0; + h_cfg.backlight = 100; + h_cfg.autohosoff = 0; + h_cfg.autonogc = 1; + h_cfg.brand = NULL; + h_cfg.tagline = NULL; + h_cfg.errors = 0; + h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; + h_cfg.rcm_patched = true; + h_cfg.emummc_force_disable = false; + + sd_power_cycle_time_start = 0xFFFFFFF; +} + +int create_config_entry() +{ + if (!sd_mount()) + return 1; + + char lbuf[32]; + FIL fp; + bool mainIniFound = false; + + LIST_INIT(ini_sections); + + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + mainIniFound = true; + else + { + u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); + if (res == FR_NO_FILE || res == FR_NO_PATH) + { + f_mkdir("bootloader"); + f_mkdir("bootloader/ini"); + f_mkdir("bootloader/payloads"); + f_mkdir("bootloader/sys"); + } + else + { + if (!res) + f_close(&fp); + return 1; + } + } + + if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return 1; + // Add config entry. + f_puts("[config]\nautoboot=", &fp); + itoa(h_cfg.autoboot, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); + itoa(h_cfg.autoboot_list, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbootwait=", &fp); + itoa(h_cfg.bootwait, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nverification=", &fp); + itoa(h_cfg.verification, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbacklight=", &fp); + itoa(h_cfg.backlight, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautohosoff=", &fp); + itoa(h_cfg.autohosoff, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautonogc=", &fp); + itoa(h_cfg.autonogc, lbuf, 10); + f_puts(lbuf, &fp); + if (h_cfg.brand) + { + f_puts("\nbrand=", &fp); + f_puts(h_cfg.brand, &fp); + } + if (h_cfg.tagline) + { + f_puts("\ntagline=", &fp); + f_puts(h_cfg.tagline, &fp); + } + f_puts("\n", &fp); + + if (mainIniFound) + { + // Re-construct existing entries. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + switch (ini_sec->type) + { + case INI_CHOICE: // Re-construct Boot entry [ ]. + f_puts("[", &fp); + f_puts(ini_sec->name, &fp); + f_puts("]\n", &fp); + // Re-construct boot entry's config. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + f_puts(kv->key, &fp); + f_puts("=", &fp); + f_puts(kv->val, &fp); + f_puts("\n", &fp); + } + break; + case INI_CAPTION: // Re-construct caption entry { }. + f_puts("{", &fp); + f_puts(ini_sec->name, &fp); + f_puts("}\n", &fp); + break; + case INI_NEWLINE: // Re-construct cosmetic newline \n. + f_puts("\n", &fp); + break; + case INI_COMMENT: // Re-construct comment entry #. + f_puts("#", &fp); + f_puts(ini_sec->name, &fp); + f_puts("\n", &fp); + break; + } + } + } + + f_close(&fp); + sd_unmount(); + + return 0; +} + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +static void _save_config() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (!create_config_entry()) + gfx_puts("\nConfiguration was saved!\n"); + else + EPRINTF("\nConfiguration saving failed!"); + gfx_puts("\nPress any key..."); +} + +static void _config_autoboot_list(void *ent) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) + boot_text[(i - 1) * 512] = ' '; + + else + boot_text[(i - 1) * 512] = '*'; + memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1); + boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0; + ments[i].caption = &boot_text[(i - 1) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 1]; + i++; + + if ((i - 1) > max_entries) + break; + } + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 1; + _save_config(); + + ment_t *tmp = (ment_t *)ent; + tmp->data = NULL; + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); +} + +void config_autoboot() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (!h_cfg.autoboot) + ments[2].caption = "*Disable"; + else + ments[2].caption = " Disable"; + ments[2].data = &boot_values[0]; + + ments[3].type = MENT_HDLR_RE; + if (h_cfg.autoboot_list) + ments[3].caption = "*More configs..."; + else + ments[3].caption = " More configs..."; + ments[3].handler = _config_autoboot_list; + ments[3].data = (void *)0xCAFE; + + ments[4].type = MENT_CHGLINE; + + u32 i = 5; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) + boot_text[(i - 4) * 512] = ' '; + + else + boot_text[(i - 4) * 512] = '*'; + memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1); + boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0; + ments[i].caption = &boot_text[(i - 4) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 4]; + i++; + + if ((i - 4) > max_entries) + break; + } + } + if (i < 6 && !h_cfg.autoboot_list) + { + ments[i].type = MENT_CAPTION; + ments[i].caption = "No main configurations found..."; + ments[i].color = 0xFFFFDD00; + i++; + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 0; + _save_config(); + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); + + if (temp_autoboot == NULL) + return; +} + +void config_bootdelay() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 delay_entries = 6; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); + u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); + char *delay_text = (char *)malloc(32 * delay_entries); + + for (u32 j = 0; j < delay_entries; j++) + delay_values[j] = j; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (h_cfg.bootwait) + ments[2].caption = " 0 seconds (Bootlogo disabled)"; + else + ments[2].caption = "*0 seconds (Bootlogo disabled)"; + ments[2].data = &delay_values[0]; + + u32 i = 0; + for (i = 1; i < delay_entries; i++) + { + if (h_cfg.bootwait != i) + delay_text[i * 32] = ' '; + else + delay_text[i * 32] = '*'; + delay_text[i * 32 + 1] = i + '0'; + memcpy(delay_text + i * 32 + 2, " seconds", 9); + + ments[i + 2].type = MENT_DATA; + ments[i + 2].caption = delay_text + i * 32; + ments[i + 2].data = &delay_values[i]; + } + + memset(&ments[i + 2], 0, sizeof(ment_t)); + menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; + + u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); + if (temp_bootwait != NULL) + { + h_cfg.bootwait = *(u32 *)temp_bootwait; + _save_config(); + } + + free(ments); + free(delay_values); + free(delay_text); + + if (temp_bootwait == NULL) + return; + 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; + + memcpy(vr_text, " Disable (Fastest - Unsafe)", 28); + memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23); + memcpy(vr_text + 128, " Full (Slow - Safe)", 23); + + for (u32 i = 0; i < 3; i++) + { + if (h_cfg.verification != i) + vr_text[64 * i] = ' '; + 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() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 bri_entries = 11; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); + u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); + char *bri_text = (char *)malloc(8 * bri_entries); + + for (u32 j = 1; j < bri_entries; j++) + bri_values[j] = j * 10; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 0; + for (i = 1; i < bri_entries; i++) + { + if ((h_cfg.backlight / 20) != i) + bri_text[i * 32] = ' '; + else + bri_text[i * 32] = '*'; + + if (i < 10) + { + bri_text[i * 32 + 1] = i + '0'; + memcpy(bri_text + i * 32 + 2, "0%", 3); + } + else + memcpy(bri_text + i * 32 + 1, "100%", 5); + + ments[i + 1].type = MENT_DATA; + ments[i + 1].caption = bri_text + i * 32; + ments[i + 1].data = &bri_values[i]; + } + + memset(&ments[i + 1], 0, sizeof(ment_t)); + menu_t menu = {ments, "Backlight brightness", 0, 0}; + + u32 *temp_backlight = (u32 *)tui_do_menu(&menu); + if (temp_backlight != NULL) + { + h_cfg.backlight = (*(u32 *)temp_backlight) * 2; + _save_config(); + } + + free(ments); + free(bri_values); + free(bri_text); + + if (temp_backlight == NULL) + return; + btn_wait(); +} + +void config_auto_hos_poweroff() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); + u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); + + for (u32 j = 0; j < 3; j++) + { + hp_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &hp_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autohosoff == 1) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Enable"; + ments[4].caption = " Enable (No logo)"; + } + else if (h_cfg.autohosoff >= 2) + { + ments[2].caption = " Disable"; + ments[3].caption = " Enable"; + ments[4].caption = "*Enable (No logo)"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Enable"; + ments[4].caption = " Enable (No logo)"; + } + + memset(&ments[5], 0, sizeof(ment_t)); + menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; + + u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); + if (temp_autohosoff != NULL) + { + h_cfg.autohosoff = *(u32 *)temp_autohosoff; + _save_config(); + } + + free(ments); + free(hp_values); + + if (temp_autohosoff == NULL) + return; + btn_wait(); +} + +void config_nogc() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); + u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); + + for (u32 j = 0; j < 2; j++) + { + cb_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &cb_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autonogc) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Auto"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Auto"; + } + + memset(&ments[4], 0, sizeof(ment_t)); + menu_t menu = {ments, "No Gamecard", 0, 0}; + + u32 *temp_nogc = (u32 *)tui_do_menu(&menu); + if (temp_nogc != NULL) + { + h_cfg.autonogc = *(u32 *)temp_nogc; + _save_config(); + } + + free(ments); + free(cb_values); + + if (temp_nogc == NULL) + return; + btn_wait(); +} + +#pragma GCC pop_options diff --git a/source/config/config.h b/source/config/config.h new file mode 100644 index 0000000..8cd34e1 --- /dev/null +++ b/source/config/config.h @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "../utils/types.h" + +typedef struct _hekate_config +{ + // Non-volatile config. + u32 autoboot; + u32 autoboot_list; + u32 bootwait; + u32 verification; + u32 backlight; + u32 autohosoff; + u32 autonogc; + char *brand; + char *tagline; + // Global temporary config. + bool se_keygen_done; + bool sept_run; + bool emummc_force_disable; + bool rcm_patched; + u32 sbar_time_keeping; + u32 errors; +} hekate_config; + +typedef enum +{ + ERR_LIBSYS_LP0 = (1 << 0), +} hsysmodule_t; + +void set_default_configuration(); +int create_config_entry(); +void config_autoboot(); +void config_bootdelay(); +void config_verification(); +void config_backlight(); +void config_auto_hos_poweroff(); +void config_nogc(); + +#endif /* _CONFIG_H_ */ diff --git a/source/config/ini.c b/source/config/ini.c new file mode 100644 index 0000000..f033994 --- /dev/null +++ b/source/config/ini.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (C) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ini.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/dirlist.h" + +static char *_strdup(char *str) +{ + if (!str) + return NULL; + + // Remove starting space. + if (str[0] == ' ' && strlen(str)) + str++; + + char *res = (char *)malloc(strlen(str) + 1); + strcpy(res, str); + + // Remove trailing space. + if (strlen(res) && res[strlen(res) - 1] == ' ') + res[strlen(res) - 1] = 0; + + return res; +} + +u32 _find_section_name(char *lbuf, u32 lblen, char schar) +{ + u32 i; + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + ; + lbuf[i] = 0; + + return i; +} + +ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) +{ + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(name); + csec->type = type; + + return csec; +} + +int ini_parse(link_t *dst, char *ini_path, bool is_dir) +{ + u32 lblen; + u32 pathlen = strlen(ini_path); + u32 k = 0; + char lbuf[512]; + char *filelist = NULL; + FIL fp; + ini_sec_t *csec = NULL; + + char *filename = (char *)malloc(256); + + memcpy(filename, ini_path, pathlen + 1); + + // Get all ini filenames. + if (is_dir) + { + filelist = dirlist(filename, "*.ini", false); + if (!filelist) + { + free(filename); + return 0; + } + memcpy(filename + pathlen, "/", 2); + pathlen++; + } + + do + { + // Copy ini filename in path string. + if (is_dir) + { + if (filelist[k * 256]) + { + memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1); + k++; + } + else + break; + } + + // Open ini. + if (f_open(&fp, filename, FA_READ) != FR_OK) + { + free(filelist); + free(filename); + + return 0; + } + + do + { + // Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + // Remove trailing newline. + if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') // Create new section. + { + _find_section_name(lbuf, lblen, ']'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); + list_init(&csec->kvs); + } + else if (lblen > 2 && lbuf[0] == '{') //Create new caption. + { + _find_section_name(lbuf, lblen, '}'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); + csec->color = 0xFF0AB9E6; + } + else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. + { + _find_section_name(lbuf, lblen, '\0'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); + } + else if (lblen < 2) + { + csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); + } + else if (csec && csec->type == INI_CHOICE) //Extract key/value. + { + u32 i = _find_section_name(lbuf, lblen, '='); + + ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); + kv->key = _strdup(&lbuf[0]); + kv->val = _strdup(&lbuf[i + 1]); + list_append(&csec->kvs, &kv->link); + } + } while (!f_eof(&fp)); + + f_close(&fp); + + if (csec) + { + list_append(dst, &csec->link); + if (is_dir) + csec = NULL; + } + } while (is_dir); + + free(filename); + free(filelist); + + return 1; +} + +char *ini_check_payload_section(ini_sec_t *cfg) +{ + if (cfg == NULL) + return NULL; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) + { + if (!strcmp("payload", kv->key)) + return kv->val; + } + + return NULL; +} diff --git a/source/config/ini.h b/source/config/ini.h new file mode 100644 index 0000000..318adf0 --- /dev/null +++ b/source/config/ini.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (C) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _INI_H_ +#define _INI_H_ + +#include "../utils/types.h" +#include "../utils/list.h" + +#define INI_CHOICE 3 +#define INI_CAPTION 5 +#define INI_CHGLINE 6 +#define INI_NEWLINE 0xFE +#define INI_COMMENT 0xFF + +typedef struct _ini_kv_t +{ + char *key; + char *val; + link_t link; +} ini_kv_t; + +typedef struct _ini_sec_t +{ + char *name; + link_t kvs; + link_t link; + u32 type; + u32 color; +} ini_sec_t; + +int ini_parse(link_t *dst, char *ini_path, bool is_dir); +char *ini_check_payload_section(ini_sec_t *cfg); + +#endif + diff --git a/source/keys/keys.c b/source/keys/keys.c index 9f3a135..6572449 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -15,6 +15,8 @@ */ #include "keys.h" + +#include "../config/config.h" #include "../gfx/di.h" #include "../gfx/gfx.h" #include "../hos/pkg1.h" @@ -45,16 +47,21 @@ extern bool sd_mount(); extern void sd_unmount(); extern int sd_save_to_file(void *buf, u32 size, const char *filename); +extern hekate_config h_cfg; + u32 _key_count = 0; sdmmc_storage_t storage; emmc_part_t *system_part; +u32 start_time, end_time; #define TPRINTF(text) \ - end_time = get_tmr_ms(); \ - gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000) + end_time = get_tmr_us(); \ + gfx_printf(text" done in %d us\n", end_time - start_time); \ + start_time = get_tmr_us() #define TPRINTFARGS(text, args...) \ - end_time = get_tmr_ms(); \ - gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000) + end_time = get_tmr_us(); \ + gfx_printf(text" done in %d us\n", args, end_time - start_time); \ + start_time = get_tmr_us() #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) #define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer) @@ -104,14 +111,15 @@ void dump_keys() { gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); - u32 start_time = get_tmr_ms(), - end_time, - retries = 0; + start_time = get_tmr_us(); + u32 retries = 0; + u32 color_idx = 0; tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); @@ -151,7 +159,7 @@ void dump_keys() { f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); } - if (!(EMC(EMC_SCRATCH0) & EMC_SEPT_RUN)) { + if (!h_cfg.sept_run) { // bundle lp0 fw for sept instead of loading it from SD as hekate does sdram_lp0_save_params(sdram_get_params_patched()); FIL fp; @@ -167,8 +175,10 @@ void dump_keys() { u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); f_close(&fp); - gfx_printf("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]); - gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]); + gfx_printf("%k\nFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); + color_idx += 2; + gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); + color_idx += 2; sdmmc_storage_end(&storage); if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) goto out_wait; @@ -207,7 +217,7 @@ get_tsec: ; goto out_wait; } - TPRINTFARGS("%kTSEC key(s)... ", colors[0]); + TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); // Master key derivation if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { @@ -288,7 +298,7 @@ get_tsec: ; } free(keyblob_block); - TPRINTFARGS("%kMaster keys... ", colors[1]); + TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); /* key = unwrap(source, wrapped_key): key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key @@ -378,7 +388,7 @@ get_tsec: ; goto pkg2_done; } - TPRINTFARGS("%kDecrypt pkg2... ", colors[2]); + TPRINTFARGS("%kDecrypt pkg2... ", colors[(color_idx++) % 6]); LIST_INIT(kip1_info); bool new_pkg2; @@ -399,7 +409,7 @@ get_tsec: ; } pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data - TPRINTFARGS("%kDecompress FS...", colors[3]); + TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]); u8 hash_index = 0, hash_max = 9, hash_order[10], key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20}; @@ -497,7 +507,7 @@ pkg2_done: free(pkg2); free(ki); - TPRINTFARGS("%kFS keys... ", colors[4]); + TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { _generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source); @@ -699,6 +709,12 @@ pkg2_done: f_closedir(&dir); free(dec_header); + if (memcmp(pkg1_id->id, "2016", 4)) { + TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]); + } else { + TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]); + } + if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to locate SD seed. Skipping."); goto dismount; @@ -728,17 +744,13 @@ pkg2_done: } f_close(&fp); + TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); + dismount: f_mount(NULL, "emmc:", 1); nx_emmc_gpt_free(&gpt); sdmmc_storage_end(&storage); - if (memcmp(pkg1_id->id, "2016", 4)) { - TPRINTFARGS("%kES & SSL keys...", colors[5]); - } else { - TPRINTFARGS("%kSSL keys... ", colors[5]); - } - // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { for (u32 i = 0; i < 0x10; i++) @@ -816,7 +828,8 @@ key_output: ; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; - TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]); + TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[(color_idx) % 6], _key_count, colors[(color_idx + 1) % 6]); + color_idx += 2; f_mkdir("switch"); char keyfile_path[30] = "sd:/switch/"; @@ -825,13 +838,13 @@ key_output: ; else sprintf(&keyfile_path[11], "dev.keys"); if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { - gfx_printf("%kWrote %d bytes to %s\n", colors[2], (u32)fno.fsize, keyfile_path); + gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else EPRINTF("Failed to save keys to SD."); sd_unmount(); out_wait: - gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]); + gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); u32 btn = btn_wait(); if (btn & BTN_VOL_UP) diff --git a/source/main.c b/source/main.c index 587d930..fb03dc7 100644 --- a/source/main.c +++ b/source/main.c @@ -18,6 +18,7 @@ #include +#include "config/config.h" #include "gfx/di.h" #include "gfx/gfx.h" #include "libs/fatfs/ff.h" @@ -36,6 +37,7 @@ sdmmc_storage_t sd_storage; __attribute__ ((aligned (16))) FATFS sd_fs; static bool sd_mounted; +hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; bool sd_mount() @@ -154,6 +156,8 @@ void ipl_main() pivot_stack(IPL_STACK_TOP); heap_init(IPL_HEAP_START); + set_default_configuration(); + display_init(); u32 *fb = display_init_framebuffer(); gfx_init_ctxt(fb, 720, 1280, 720); diff --git a/source/utils/dirlist.c b/source/utils/dirlist.c new file mode 100644 index 0000000..8e6f3cc --- /dev/null +++ b/source/utils/dirlist.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/types.h" + +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles) +{ + u8 max_entries = 61; + + int res = 0; + u32 i = 0, j = 0, k = 0; + DIR dir; + FILINFO fno; + + char *dir_entries = (char *)calloc(max_entries, 256); + char *temp = (char *)calloc(1, 256); + + if (!pattern && !f_opendir(&dir, directory)) + { + for (;;) + { + res = f_readdir(&dir, &fno); + if (res || !fno.fname[0]) + break; + if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1); + k++; + if (k > (max_entries - 1)) + break; + } + } + f_closedir(&dir); + } + else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0]) + { + do + { + if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1); + k++; + if (k > (max_entries - 1)) + break; + } + res = f_findnext(&dir, &fno); + } while (fno.fname[0] && !res); + f_closedir(&dir); + } + + if (!k) + { + free(temp); + free(dir_entries); + + return NULL; + } + + // Reorder ini files by ASCII ordering. + for (i = 0; i < k - 1 ; i++) + { + for (j = i + 1; j < k; j++) + { + if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + { + memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1); + memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1); + memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1); + } + } + } + + free(temp); + + return dir_entries; +} diff --git a/source/utils/dirlist.h b/source/utils/dirlist.h new file mode 100644 index 0000000..4fb9af7 --- /dev/null +++ b/source/utils/dirlist.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../utils/types.h" + +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles); From 250f068211baa09b12e0973824d2894321aa2ebf Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 17 Sep 2019 09:51:30 -0600 Subject: [PATCH 003/166] Add menu and option to dump keys from emuMMC --- source/config/config.c | 614 ------------------------------------- source/config/config.h | 7 - source/gfx/tui.c | 227 ++++++++++++++ source/gfx/tui.h | 66 ++++ source/keys/keys.c | 46 +-- source/libs/fatfs/diskio.c | 5 +- source/libs/fatfs/ffconf.h | 6 +- source/main.c | 84 ++++- source/power/max17050.c | 5 + source/storage/emummc.c | 266 ++++++++++++++++ source/storage/emummc.h | 59 ++++ source/storage/nx_emmc.c | 5 +- source/utils/types.h | 4 + 13 files changed, 726 insertions(+), 668 deletions(-) create mode 100644 source/gfx/tui.c create mode 100644 source/gfx/tui.h create mode 100644 source/storage/emummc.c create mode 100644 source/storage/emummc.h diff --git a/source/config/config.c b/source/config/config.c index f9df696..2fa964b 100644 --- a/source/config/config.c +++ b/source/config/config.c @@ -20,7 +20,6 @@ #include "config.h" #include "ini.h" #include "../gfx/gfx.h" -#include "../gfx/tui.h" #include "../libs/fatfs/ff.h" #include "../soc/t210.h" #include "../storage/sdmmc.h" @@ -53,616 +52,3 @@ void set_default_configuration() sd_power_cycle_time_start = 0xFFFFFFF; } -int create_config_entry() -{ - if (!sd_mount()) - return 1; - - char lbuf[32]; - FIL fp; - bool mainIniFound = false; - - LIST_INIT(ini_sections); - - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - mainIniFound = true; - else - { - u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); - if (res == FR_NO_FILE || res == FR_NO_PATH) - { - f_mkdir("bootloader"); - f_mkdir("bootloader/ini"); - f_mkdir("bootloader/payloads"); - f_mkdir("bootloader/sys"); - } - else - { - if (!res) - f_close(&fp); - return 1; - } - } - - if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) - return 1; - // Add config entry. - f_puts("[config]\nautoboot=", &fp); - itoa(h_cfg.autoboot, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautoboot_list=", &fp); - itoa(h_cfg.autoboot_list, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbootwait=", &fp); - itoa(h_cfg.bootwait, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nverification=", &fp); - itoa(h_cfg.verification, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbacklight=", &fp); - itoa(h_cfg.backlight, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautohosoff=", &fp); - itoa(h_cfg.autohosoff, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautonogc=", &fp); - itoa(h_cfg.autonogc, lbuf, 10); - f_puts(lbuf, &fp); - if (h_cfg.brand) - { - f_puts("\nbrand=", &fp); - f_puts(h_cfg.brand, &fp); - } - if (h_cfg.tagline) - { - f_puts("\ntagline=", &fp); - f_puts(h_cfg.tagline, &fp); - } - f_puts("\n", &fp); - - if (mainIniFound) - { - // Re-construct existing entries. - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - switch (ini_sec->type) - { - case INI_CHOICE: // Re-construct Boot entry [ ]. - f_puts("[", &fp); - f_puts(ini_sec->name, &fp); - f_puts("]\n", &fp); - // Re-construct boot entry's config. - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - f_puts(kv->key, &fp); - f_puts("=", &fp); - f_puts(kv->val, &fp); - f_puts("\n", &fp); - } - break; - case INI_CAPTION: // Re-construct caption entry { }. - f_puts("{", &fp); - f_puts(ini_sec->name, &fp); - f_puts("}\n", &fp); - break; - case INI_NEWLINE: // Re-construct cosmetic newline \n. - f_puts("\n", &fp); - break; - case INI_COMMENT: // Re-construct comment entry #. - f_puts("#", &fp); - f_puts(ini_sec->name, &fp); - f_puts("\n", &fp); - break; - } - } - } - - f_close(&fp); - sd_unmount(); - - return 0; -} - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -static void _save_config() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - if (!create_config_entry()) - gfx_puts("\nConfiguration was saved!\n"); - else - EPRINTF("\nConfiguration saving failed!"); - gfx_puts("\nPress any key..."); -} - -static void _config_autoboot_list(void *ent) -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(512 * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/ini", true)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 2; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) - boot_text[(i - 1) * 512] = ' '; - - else - boot_text[(i - 1) * 512] = '*'; - memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1); - boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0; - ments[i].caption = &boot_text[(i - 1) * 512]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 1]; - i++; - - if ((i - 1) > max_entries) - break; - } - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 1; - _save_config(); - - ment_t *tmp = (ment_t *)ent; - tmp->data = NULL; - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); -} - -void config_autoboot() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(512 * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (!h_cfg.autoboot) - ments[2].caption = "*Disable"; - else - ments[2].caption = " Disable"; - ments[2].data = &boot_values[0]; - - ments[3].type = MENT_HDLR_RE; - if (h_cfg.autoboot_list) - ments[3].caption = "*More configs..."; - else - ments[3].caption = " More configs..."; - ments[3].handler = _config_autoboot_list; - ments[3].data = (void *)0xCAFE; - - ments[4].type = MENT_CHGLINE; - - u32 i = 5; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) - boot_text[(i - 4) * 512] = ' '; - - else - boot_text[(i - 4) * 512] = '*'; - memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1); - boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0; - ments[i].caption = &boot_text[(i - 4) * 512]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 4]; - i++; - - if ((i - 4) > max_entries) - break; - } - } - if (i < 6 && !h_cfg.autoboot_list) - { - ments[i].type = MENT_CAPTION; - ments[i].caption = "No main configurations found..."; - ments[i].color = 0xFFFFDD00; - i++; - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 0; - _save_config(); - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); - - if (temp_autoboot == NULL) - return; -} - -void config_bootdelay() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 delay_entries = 6; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); - u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); - char *delay_text = (char *)malloc(32 * delay_entries); - - for (u32 j = 0; j < delay_entries; j++) - delay_values[j] = j; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (h_cfg.bootwait) - ments[2].caption = " 0 seconds (Bootlogo disabled)"; - else - ments[2].caption = "*0 seconds (Bootlogo disabled)"; - ments[2].data = &delay_values[0]; - - u32 i = 0; - for (i = 1; i < delay_entries; i++) - { - if (h_cfg.bootwait != i) - delay_text[i * 32] = ' '; - else - delay_text[i * 32] = '*'; - delay_text[i * 32 + 1] = i + '0'; - memcpy(delay_text + i * 32 + 2, " seconds", 9); - - ments[i + 2].type = MENT_DATA; - ments[i + 2].caption = delay_text + i * 32; - ments[i + 2].data = &delay_values[i]; - } - - memset(&ments[i + 2], 0, sizeof(ment_t)); - menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; - - u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); - if (temp_bootwait != NULL) - { - h_cfg.bootwait = *(u32 *)temp_bootwait; - _save_config(); - } - - free(ments); - free(delay_values); - free(delay_text); - - if (temp_bootwait == NULL) - return; - 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; - - memcpy(vr_text, " Disable (Fastest - Unsafe)", 28); - memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23); - memcpy(vr_text + 128, " Full (Slow - Safe)", 23); - - for (u32 i = 0; i < 3; i++) - { - if (h_cfg.verification != i) - vr_text[64 * i] = ' '; - 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() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 bri_entries = 11; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); - u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); - char *bri_text = (char *)malloc(8 * bri_entries); - - for (u32 j = 1; j < bri_entries; j++) - bri_values[j] = j * 10; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 0; - for (i = 1; i < bri_entries; i++) - { - if ((h_cfg.backlight / 20) != i) - bri_text[i * 32] = ' '; - else - bri_text[i * 32] = '*'; - - if (i < 10) - { - bri_text[i * 32 + 1] = i + '0'; - memcpy(bri_text + i * 32 + 2, "0%", 3); - } - else - memcpy(bri_text + i * 32 + 1, "100%", 5); - - ments[i + 1].type = MENT_DATA; - ments[i + 1].caption = bri_text + i * 32; - ments[i + 1].data = &bri_values[i]; - } - - memset(&ments[i + 1], 0, sizeof(ment_t)); - menu_t menu = {ments, "Backlight brightness", 0, 0}; - - u32 *temp_backlight = (u32 *)tui_do_menu(&menu); - if (temp_backlight != NULL) - { - h_cfg.backlight = (*(u32 *)temp_backlight) * 2; - _save_config(); - } - - free(ments); - free(bri_values); - free(bri_text); - - if (temp_backlight == NULL) - return; - btn_wait(); -} - -void config_auto_hos_poweroff() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); - u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); - - for (u32 j = 0; j < 3; j++) - { - hp_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &hp_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autohosoff == 1) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Enable"; - ments[4].caption = " Enable (No logo)"; - } - else if (h_cfg.autohosoff >= 2) - { - ments[2].caption = " Disable"; - ments[3].caption = " Enable"; - ments[4].caption = "*Enable (No logo)"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Enable"; - ments[4].caption = " Enable (No logo)"; - } - - memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; - - u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); - if (temp_autohosoff != NULL) - { - h_cfg.autohosoff = *(u32 *)temp_autohosoff; - _save_config(); - } - - free(ments); - free(hp_values); - - if (temp_autohosoff == NULL) - return; - btn_wait(); -} - -void config_nogc() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); - u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); - - for (u32 j = 0; j < 2; j++) - { - cb_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &cb_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autonogc) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Auto"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Auto"; - } - - memset(&ments[4], 0, sizeof(ment_t)); - menu_t menu = {ments, "No Gamecard", 0, 0}; - - u32 *temp_nogc = (u32 *)tui_do_menu(&menu); - if (temp_nogc != NULL) - { - h_cfg.autonogc = *(u32 *)temp_nogc; - _save_config(); - } - - free(ments); - free(cb_values); - - if (temp_nogc == NULL) - return; - btn_wait(); -} - -#pragma GCC pop_options diff --git a/source/config/config.h b/source/config/config.h index 8cd34e1..1f6c36d 100644 --- a/source/config/config.h +++ b/source/config/config.h @@ -46,12 +46,5 @@ typedef enum } hsysmodule_t; void set_default_configuration(); -int create_config_entry(); -void config_autoboot(); -void config_bootdelay(); -void config_verification(); -void config_backlight(); -void config_auto_hos_poweroff(); -void config_nogc(); #endif /* _CONFIG_H_ */ diff --git a/source/gfx/tui.c b/source/gfx/tui.c new file mode 100644 index 0000000..4960c8c --- /dev/null +++ b/source/gfx/tui.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "di.h" +#include "tui.h" +#include "../utils/btn.h" +#include "../config/config.h" +#include "../power/max17050.h" +#include "../utils/util.h" + +#ifdef MENU_LOGO_ENABLE +extern u8 *Kc_MENU_LOGO; +#define X_MENU_LOGO 119 +#define Y_MENU_LOGO 57 +#define X_POS_MENU_LOGO 577 +#define Y_POS_MENU_LOGO 1179 +#endif //MENU_LOGO_ENABLE + +extern hekate_config h_cfg; + +void tui_sbar(bool force_update) +{ + u32 cx, cy; + + u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping; + if (!force_update) + if (timePassed < 5) + return; + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 16; + h_cfg.sbar_time_keeping = get_tmr_s(); + + u32 battPercent = 0; + int battVoltCurr = 0; + + gfx_con_getpos(&cx, &cy); + gfx_con_setpos(0, 1260); + + max17050_get_property(MAX17050_RepSOC, (int *)&battPercent); + max17050_get_property(MAX17050_VCELL, &battVoltCurr); + + gfx_clear_partial_grey(0x30, 1256, 24); + gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888, + (battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr); + + max17050_get_property(MAX17050_Current, &battVoltCurr); + + if (battVoltCurr >= 0) + gfx_printf(" %k+%d mA%k%K\n", + 0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B); + else + gfx_printf(" %k-%d mA%k%K\n", + 0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B); + gfx_con.fntsz = prevFontSize; + gfx_con_setpos(cx, cy); +} + +void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) +{ + u32 cx, cy; + if (val > 200) + val = 200; + + gfx_con_getpos(&cx, &cy); + + gfx_con_setpos(x, y); + + gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC); + + x += 7 * gfx_con.fntsz; + + for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) + { + gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol); + gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol); + } + + gfx_con_setpos(cx, cy); + + // Update status bar. + tui_sbar(false); +} + +void *tui_do_menu(menu_t *menu) +{ + int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF; + + gfx_clear_partial_grey(0x1B, 0, 1256); + tui_sbar(true); + +#ifdef MENU_LOGO_ENABLE + gfx_set_rect_rgb(Kc_MENU_LOGO, + X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + + while (true) + { + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_con_setpos(menu->x, menu->y); + gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", + colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); + + // Skip caption or seperator lines selection. + while (menu->ents[idx].type == MENT_CAPTION || + menu->ents[idx].type == MENT_CHGLINE) + { + if (prev_idx <= idx || (!idx && prev_idx == cnt - 1)) + { + idx++; + if (idx > (cnt - 1)) + { + idx = 0; + prev_idx = 0; + } + } + else + { + idx--; + if (idx < 0) + { + idx = cnt - 1; + prev_idx = cnt; + } + } + } + prev_idx = idx; + + // Draw the menu. + for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++) + { + if (cnt == idx) + gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); + else + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + // if (menu->ents[cnt].type == MENT_CAPTION) + // gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption); + if (menu->ents[cnt].type != MENT_CHGLINE) { + if (cnt == idx) + gfx_printf(" %s", menu->ents[cnt].caption); + else + gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);//gfx_printf(" %s", menu->ents[cnt].caption); + } + if(menu->ents[cnt].type == MENT_MENU) + gfx_printf("%k...", 0xFF0099EE); + gfx_printf(" \n"); + } + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_putc('\n'); + + // Print help and battery status. + gfx_con_setpos(0, 1127); + if (h_cfg.emummc_force_disable) + gfx_printf("%kNo emuMMC config found.\n", 0xFF800000); + gfx_con_setpos(0, 1191); + gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC); + + display_backlight_brightness(h_cfg.backlight, 1000); + + // Wait for user command. + u32 btn = btn_wait(); + + if (btn & BTN_VOL_DOWN && idx < (cnt - 1)) + idx++; + else if (btn & BTN_VOL_DOWN && idx == (cnt - 1)) + { + idx = 0; + prev_idx = -1; + } + if (btn & BTN_VOL_UP && idx > 0) + idx--; + else if (btn & BTN_VOL_UP && idx == 0) + { + idx = cnt - 1; + prev_idx = cnt; + } + if (btn & BTN_POWER) + { + ment_t *ent = &menu->ents[idx]; + switch (ent->type) + { + case MENT_HANDLER: + ent->handler(ent->data); + break; + case MENT_MENU: + return tui_do_menu(ent->menu); + break; + case MENT_DATA: + return ent->data; + break; + case MENT_BACK: + return NULL; + break; + case MENT_HDLR_RE: + ent->handler(ent); + if (!ent->data) + return NULL; + break; + default: + break; + } + gfx_con.fntsz = 16; + gfx_clear_partial_grey(0x1B, 0, 1256); +#ifdef MENU_LOGO_ENABLE + gfx_set_rect_rgb(Kc_MENU_LOGO, + X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + } + tui_sbar(false); + } + + return NULL; +} diff --git a/source/gfx/tui.h b/source/gfx/tui.h new file mode 100644 index 0000000..2b7d3f7 --- /dev/null +++ b/source/gfx/tui.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (C) 2018 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _TUI_H_ +#define _TUI_H_ + +#include "../utils/types.h" +#include "gfx.h" + +#define MENT_END 0 +#define MENT_HANDLER 1 +#define MENT_MENU 2 +#define MENT_DATA 3 +#define MENT_BACK 4 +#define MENT_CAPTION 5 +#define MENT_CHGLINE 6 +#define MENT_HDLR_RE 7 + +typedef struct _ment_t +{ + u32 type; + const char *caption; + u32 color; + void *data; + union + { + void(*handler)(void *); + struct _menu_t *menu; + }; +} ment_t; + +typedef struct _menu_t +{ + ment_t *ents; + const char *caption; + u32 x; + u32 y; +} menu_t; + +#define MDEF_END() {MENT_END} +#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } } +#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } } +#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } } +#define MDEF_BACK() { MENT_BACK, "Back" } +#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color } +#define MDEF_CHGLINE() {MENT_CHGLINE} + +void tui_sbar(bool force_update); +void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol); +void *tui_do_menu(menu_t *menu); + +#endif diff --git a/source/keys/keys.c b/source/keys/keys.c index 6572449..6c25aec 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -19,6 +19,7 @@ #include "../config/config.h" #include "../gfx/di.h" #include "../gfx/gfx.h" +#include "../gfx/tui.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/sept.h" @@ -32,6 +33,7 @@ #include "../soc/fuse.h" #include "../soc/smmu.h" #include "../soc/t210.h" +#include "../storage/emummc.h" #include "../storage/nx_emmc.h" #include "../storage/sdmmc.h" #include "../utils/btn.h" @@ -91,8 +93,6 @@ static u8 temp_key[0x10], package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; -static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; - // key functions static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; static void _save_key(const char *name, const void *data, const u32 len, char *outbuf); @@ -105,26 +105,27 @@ static void _update_ctr(u8 *ctr, u32 ofs); void dump_keys() { display_backlight_brightness(100, 1000); - gfx_clear_grey(0x1B); + gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); start_time = get_tmr_us(); + u32 begin_time = get_tmr_us(); u32 retries = 0; u32 color_idx = 0; tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + emummc_storage_init_mmc(&storage, &sdmmc); TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { EPRINTF("Unknown pkg1 version."); @@ -154,6 +155,7 @@ void dump_keys() { } if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { + sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { f_unlink("sd:/sept/payload.bin"); f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); @@ -277,7 +279,7 @@ get_tsec: ; } // verify keyblob is not corrupt - sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); + emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); se_aes_key_set(3, keyblob_mac_key[i], 0x10); se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); if (memcmp(keyblob_block, keyblob_mac, 0x10)) { @@ -336,7 +338,7 @@ get_tsec: ; u8 *pkg2 = NULL; pkg2_kip1_info_t *ki = NULL; - sdmmc_storage_set_mmc_partition(&storage, 0); + emummc_storage_set_mmc_partition(&storage, 0); // Parse eMMC GPT. LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &storage); @@ -380,7 +382,7 @@ get_tsec: ; EPRINTF("Failed to derive Package2 key."); goto pkg2_done; } else if (pkg2_kb != pkg1_id->kb) - EPRINTF("Warning: Package1-Package2 mismatch."); + EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb); pkg2_hdr = pkg2_decrypt(pkg2); if (!pkg2_hdr) { @@ -749,7 +751,7 @@ pkg2_done: dismount: f_mount(NULL, "emmc:", 1); nx_emmc_gpt_free(&gpt); - sdmmc_storage_end(&storage); + emummc_storage_end(&storage); // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { @@ -828,31 +830,29 @@ key_output: ; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; - TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[(color_idx) % 6], _key_count, colors[(color_idx + 1) % 6]); - color_idx += 2; + end_time = get_tmr_us(); + gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count); + _key_count = 0; + gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time); + gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1); - f_mkdir("switch"); + f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; if (!(fuse_read_odm(4) & 3)) sprintf(&keyfile_path[11], "prod.keys"); else sprintf(&keyfile_path[11], "dev.keys"); - if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else EPRINTF("Failed to save keys to SD."); - sd_unmount(); + h_cfg.emummc_force_disable = emummc_load_cfg(); out_wait: - gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); + sd_unmount(); + gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); - u32 btn = btn_wait(); - if (btn & BTN_VOL_UP) - reboot_rcm(); - else if (btn & BTN_VOL_DOWN) - reboot_normal(); - else - power_off(); + btn_wait(); } static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) { diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index f33f011..97f8336 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -42,10 +42,11 @@ typedef struct { u32 visit_count; u8 tweak[0x10]; u8 cached_sector[0x200]; + u8 align[8]; } sector_cache_t; - + #define MAX_SEC_CACHE_ENTRIES 64 -static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000; +static sector_cache_t *sector_cache = (sector_cache_t*)0x40022000; static u32 secindex = 0; DSTATUS disk_status ( diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index ca13b33..221c909 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_STRFUNC 0 +#define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. @@ -33,7 +33,7 @@ / 2: Enable with LF-CRLF conversion. */ -#define FF_USE_FIND 0 +#define FF_USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ @@ -50,7 +50,7 @@ /* This option switches f_expand function. (0:Disable or 1:Enable) */ -#define FF_USE_CHMOD 0 +#define FF_USE_CHMOD 1 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ diff --git a/source/main.c b/source/main.c index fb03dc7..3fcdef5 100644 --- a/source/main.c +++ b/source/main.c @@ -21,13 +21,16 @@ #include "config/config.h" #include "gfx/di.h" #include "gfx/gfx.h" +#include "gfx/tui.h" #include "libs/fatfs/ff.h" #include "mem/heap.h" #include "power/max77620.h" #include "rtc/max77620-rtc.h" #include "soc/bpmp.h" #include "soc/hw_init.h" +#include "storage/emummc.h" #include "storage/sdmmc.h" +#include "utils/sprintf.h" #include "utils/util.h" #include "keys/keys.h" @@ -79,27 +82,27 @@ void sd_unmount() void *sd_file_read(const char *path, u32 *fsize) { - FIL fp; - if (f_open(&fp, path, FA_READ) != FR_OK) - return NULL; + FIL fp; + if (f_open(&fp, path, FA_READ) != FR_OK) + return NULL; - u32 size = f_size(&fp); - if (fsize) - *fsize = size; + u32 size = f_size(&fp); + if (fsize) + *fsize = size; - void *buf = malloc(size); + void *buf = malloc(size); - if (f_read(&fp, buf, size, NULL) != FR_OK) - { - free(buf); - f_close(&fp); + if (f_read(&fp, buf, size, NULL) != FR_OK) + { + free(buf); + f_close(&fp); - return NULL; - } + return NULL; + } - f_close(&fp); + f_close(&fp); - return buf; + return buf; } int sd_save_to_file(void *buf, u32 size, const char *filename) @@ -145,6 +148,34 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) } } +void dump_sysnand() +{ + h_cfg.emummc_force_disable = true; + b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); +} + +void dump_emunand() +{ + if (h_cfg.emummc_force_disable) + return; + emu_cfg.enabled = 1; + b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); +} + +ment_t ment_top[] = { + MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump keys from emuMMC", dump_emunand, COLOR_ORANGE), + MDEF_CAPTION("---------------", COLOR_YELLOW), + MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN), + MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE), + MDEF_HANDLER("Power off", power_off, COLOR_VIOLET), + MDEF_END() +}; + +menu_t menu_top = { ment_top, NULL, 0, 0 }; + #define IPL_STACK_TOP 0x4003F000 #define IPL_HEAP_START 0x90020000 @@ -166,6 +197,25 @@ void ipl_main() bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); - sd_mount(); - dump_keys(); + h_cfg.emummc_force_disable = emummc_load_cfg(); + + if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) + { + if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) + h_cfg.emummc_force_disable = true; + dump_keys(); + } + + if (h_cfg.emummc_force_disable) + { + ment_top[1].type = MENT_CAPTION; + ment_top[1].color = 0xFF555555; + ment_top[1].handler = NULL; + } + + while (true) + tui_do_menu(&menu_top); + + while (true) + bpmp_halt(); } diff --git a/source/power/max17050.c b/source/power/max17050.c index 2a2c8f6..d34c340 100644 --- a/source/power/max17050.c +++ b/source/power/max17050.c @@ -43,6 +43,9 @@ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ +#pragma GCC push_options +#pragma GCC optimize ("Os") + int max17050_get_property(enum MAX17050_reg reg, int *value) { u16 data; @@ -264,3 +267,5 @@ int max17050_fix_configuration() return 0; } + +#pragma GCC pop_options \ No newline at end of file diff --git a/source/storage/emummc.c b/source/storage/emummc.c new file mode 100644 index 0000000..deae70e --- /dev/null +++ b/source/storage/emummc.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "emummc.h" +#include "sdmmc.h" +#include "../config/config.h" +#include "../config/ini.h" +#include "../gfx/gfx.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/list.h" +#include "../utils/types.h" + +extern sdmmc_t sd_sdmmc; +extern sdmmc_storage_t sd_storage; +extern FATFS sd_fs; + +extern hekate_config h_cfg; + +extern bool sd_mount(); +extern void sd_unmount(); + +bool emummc_load_cfg() +{ + sd_mount(); + emu_cfg.enabled = 0; + emu_cfg.path = NULL; + emu_cfg.nintendo_path = NULL; + emu_cfg.sector = 0; + emu_cfg.id = 0; + emu_cfg.file_based_part_size = 0; + emu_cfg.active_part = 0; + emu_cfg.fs_ver = 0; + emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + + LIST_INIT(ini_sections); + if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (ini_sec->type == INI_CHOICE) + { + if (strcmp(ini_sec->name, "emummc")) + continue; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("enabled", kv->key)) + emu_cfg.enabled = atoi(kv->val); + else if (!strcmp("sector", kv->key)) + emu_cfg.sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_cfg.id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + emu_cfg.path = kv->val; + else if (!strcmp("nintendo_path", kv->key)) + emu_cfg.nintendo_path = kv->val; + } + break; + } + } + return 0; + } + return 1; +} + +static int emummc_raw_get_part_off(int part_idx) +{ + switch (part_idx) + { + case 0: + return 2; + case 1: + return 0; + case 2: + return 1; + } + return 2; +} + + +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +{ + FILINFO fno; + if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + { + EPRINTF("Failed to init eMMC."); + + goto out; + } + if (h_cfg.emummc_force_disable) + return 1; + + emu_cfg.active_part = 0; + if (!sd_mount()) + goto out; + + if (emu_cfg.enabled && !emu_cfg.sector) + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + EPRINTF("Failed to open eMMC folder."); + goto out; + } + f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC); + + strcat(emu_cfg.emummc_file_based_path, "/00"); + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + EPRINTF("Failed to open emuMMC rawnand."); + goto out; + } + emu_cfg.file_based_part_size = fno.fsize >> 9; + } + return 1; + +out: + return 0; +} + +int emummc_storage_end(sdmmc_storage_t *storage) +{ + sd_unmount(); + sdmmc_storage_end(storage); + + return 1; +} + +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_read(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + EPRINTF("Failed to open emuMMC image."); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_read(&fp, buf, (u64)num_sectors << 9, NULL)) + { + EPRINTF("Failed to read emuMMC image."); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } + + return 1; +} + +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_write(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE)) + { + gfx_printf("e5\n"); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_write(&fp, buf, (u64)num_sectors << 9, NULL)) + { + gfx_printf("e6\n"); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } +} + +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +{ + emu_cfg.active_part = partition; + + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + sdmmc_storage_set_mmc_partition(storage, partition); + else if (emu_cfg.sector) + return 1; + else + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + switch (partition) + { + case 0: + strcat(emu_cfg.emummc_file_based_path, "/00"); + break; + case 1: + strcat(emu_cfg.emummc_file_based_path, "/BOOT0"); + break; + case 2: + strcat(emu_cfg.emummc_file_based_path, "/BOOT1"); + break; + } + + return 1; + } + + return 1; +} diff --git a/source/storage/emummc.h b/source/storage/emummc.h new file mode 100644 index 0000000..635332f --- /dev/null +++ b/source/storage/emummc.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EMUMMC_H +#define EMUMMC_H + +#include "sdmmc.h" +#include "../utils/types.h" + +typedef enum +{ + EMUMMC_TYPE_NONE = 0, + EMUMMC_TYPE_PARTITION = 1, + EMUMMC_TYPE_FILES = 2, +} emummc_type_t; + +typedef enum { + EMUMMC_MMC_NAND = 0, + EMUMMC_MMC_SD = 1, + EMUMMC_MMC_GC = 2, +} emummc_mmc_t; + +typedef struct _emummc_cfg_t +{ + int enabled; + u64 sector; + u16 id; + char *path; + char *nintendo_path; + // Internal. + char *emummc_file_based_path; + u32 file_based_part_size; + u32 active_part; + int fs_ver; +} emummc_cfg_t; + +emummc_cfg_t emu_cfg; + +bool emummc_load_cfg(); +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); +int emummc_storage_end(sdmmc_storage_t *storage); +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); + +#endif \ No newline at end of file diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index a65dced..8e0fb63 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -17,6 +17,7 @@ #include #include "nx_emmc.h" +#include "emummc.h" #include "../mem/heap.h" #include "../utils/list.h" @@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) { u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE); - sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); + emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); gpt_header_t *hdr = (gpt_header_t *)buf; for (u32 i = 0; i < hdr->num_part_ents; i++) @@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; - return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); + return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); } int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) diff --git a/source/utils/types.h b/source/utils/types.h index 579c274..e5dcb22 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -68,6 +68,8 @@ typedef volatile unsigned char vu8; typedef volatile unsigned short vu16; typedef volatile unsigned int vu32; +static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; + typedef int bool; #define true 1 #define false 0 @@ -76,6 +78,8 @@ typedef int bool; #define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_SEPT_RUN (1 << 7) +#define EXTRA_CFG_DUMP_EMUMMC (1 << 0) + typedef struct __attribute__((__packed__)) _boot_cfg_t { u8 boot_cfg; From 1f2f0c433eb487c8cf751a3a96dd9755ed0a35a1 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 17 Sep 2019 10:03:41 -0600 Subject: [PATCH 004/166] Fix trailing whitespace --- source/gfx/di.inl | 2 +- source/gfx/gfx.c | 1 - source/gfx/tui.c | 2 +- source/hos/pkg1.c | 96 +++++----- source/hos/pkg2.c | 10 +- source/hos/sept.c | 288 ++++++++++++++--------------- source/keys/key_sources.inl | 328 +++++++++++++++++----------------- source/keys/keys.c | 2 +- source/libs/compr/blz.c | 20 +-- source/power/max17050.c | 2 +- source/rtc/max77620-rtc.c | 2 +- source/sec/se.c | 2 +- source/sec/tsec.c | 4 +- source/soc/hw_init.c | 6 +- source/soc/pinmux.h | 2 +- source/soc/t210.h | 2 +- source/storage/emummc.c | 4 +- source/storage/sdmmc.c | 4 +- source/storage/sdmmc_driver.c | 18 +- source/utils/dirlist.c | 4 +- source/utils/sprintf.c | 244 ++++++++++++------------- source/utils/sprintf.h | 48 ++--- source/utils/util.c | 4 +- 23 files changed, 547 insertions(+), 548 deletions(-) diff --git a/source/gfx/di.inl b/source/gfx/di.inl index 48cea7b..58bf442 100644 --- a/source/gfx/di.inl +++ b/source/gfx/di.inl @@ -128,7 +128,7 @@ static const cfg_op_t _display_config_2[94] = { }; //DSI Init config. -static const cfg_op_t _display_config_3[61] = { +static const cfg_op_t _display_config_3[61] = { {DSI_WR_DATA, 0}, {DSI_INT_ENABLE, 0}, {DSI_INT_STATUS, 0}, diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 62e60ca..501b6f3 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -263,7 +263,6 @@ void gfx_putc(char c) } break; } - } void gfx_puts(const char *s) diff --git a/source/gfx/tui.c b/source/gfx/tui.c index 4960c8c..ed2357a 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -83,7 +83,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC); x += 7 * gfx_con.fntsz; - + for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) { gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol); diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 3b6d6c6..5e36e05 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -1,48 +1,48 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 st4rk - * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2018 balika011 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "pkg1.h" -#include "../sec/se.h" - -static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0 }, //1.0.0 - { "20170210155124", 0 }, //2.0.0 - 2.3.0 - { "20170519101410", 1 }, //3.0.0 - { "20170710161758", 2 }, //3.0.1 - 3.0.2 - { "20170921172629", 3 }, //4.0.0 - 4.1.0 - { "20180220163747", 4 }, //5.0.0 - 5.1.0 - { "20180802162753", 5 }, //6.0.0 - 6.1.0 - { "20181107105733", 6 }, //6.2.0 - { "20181218175730", 7 }, //7.0.0 - { "20190208150037", 7 }, //7.0.1 - { "20190314172056", 7 }, //8.0.0 - { "20190531152432", 8 }, //8.1.0 - { "20190809135709", 9 }, //9.0.0 - { NULL } //End. -}; - -const pkg1_id_t *pkg1_identify(u8 *pkg1) -{ - for (u32 i = 0; _pkg1_ids[i].id; i++) - if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) - return &_pkg1_ids[i]; - return NULL; -} +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 st4rk + * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "pkg1.h" +#include "../sec/se.h" + +static const pkg1_id_t _pkg1_ids[] = { + { "20161121183008", 0 }, //1.0.0 + { "20170210155124", 0 }, //2.0.0 - 2.3.0 + { "20170519101410", 1 }, //3.0.0 + { "20170710161758", 2 }, //3.0.1 - 3.0.2 + { "20170921172629", 3 }, //4.0.0 - 4.1.0 + { "20180220163747", 4 }, //5.0.0 - 5.1.0 + { "20180802162753", 5 }, //6.0.0 - 6.1.0 + { "20181107105733", 6 }, //6.2.0 + { "20181218175730", 7 }, //7.0.0 + { "20190208150037", 7 }, //7.0.1 + { "20190314172056", 7 }, //8.0.0 + { "20190531152432", 8 }, //8.1.0 + { "20190809135709", 9 }, //9.0.0 + { NULL } //End. +}; + +const pkg1_id_t *pkg1_identify(u8 *pkg1) +{ + for (u32 i = 0; _pkg1_ids[i].id; i++) + if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + return &_pkg1_ids[i]; + return NULL; +} diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index e696122..e745cbc 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -85,19 +85,19 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) pkg2_kip1_t hdr; memcpy(&hdr, ki->kip1, sizeof(hdr)); - + unsigned int newKipSize = sizeof(hdr); for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) { u32 sectCompBit = 1u << sectIdx; // For compressed, cant get actual decompressed size without doing it, so use safe "output size". - if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) + if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) newKipSize += hdr.sections[sectIdx].size_decomp; else newKipSize += hdr.sections[sectIdx].size_comp; } - pkg2_kip1_t* newKip = malloc(newKipSize); + pkg2_kip1_t* newKip = malloc(newKipSize); unsigned char* dstDataPtr = newKip->data; const unsigned char* srcDataPtr = ki->kip1->data; for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) @@ -121,7 +121,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) //gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize); if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0) { - gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); + gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); free(newKip); return 1; @@ -149,7 +149,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) pkg2_hdr_t *pkg2_decrypt(void *data) { u8 *pdata = (u8 *)data; - + // Skip signature. pdata += 0x100; diff --git a/source/hos/sept.c b/source/hos/sept.c index 8632db7..3ec628e 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -1,145 +1,145 @@ -/* - * 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 . - */ - -#include - -#include "sept.h" -#include "../gfx/di.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../soc/hw_init.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/types.h" - -#include "../gfx/gfx.h" - -#define PATCHED_RELOC_SZ 0x94 - -#define WB_RST_ADDR 0x40010ED0 -#define WB_RST_SIZE 0x30 - -u8 warmboot_reboot[] = { - 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 - 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 - 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0xFE, 0xFF, 0xFF, 0xEA, // LOOP - 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 - 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 -}; - -#define SEPT_PRI_ADDR 0x4003F000 - -#define SEPT_PK1T_ADDR 0xC0400000 -#define SEPT_PK1T_STACK 0x40008000 -#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) -#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) -#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) -#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) - -extern boot_cfg_t b_cfg; -extern void sd_unmount(); -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); - -int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) -{ - FIL fp; - - // Copy warmboot reboot code and TSEC fw. - memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); - memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); - *(vu32 *)SEPT_TCSZ_ADDR = tsec_size; - - // Copy sept-primary. - if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) - goto error; - - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) - { - if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) - goto error; - } - - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Save auto boot config to sept payload, if any. - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t)); - - tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) - goto error; - - f_lseek(&fp, PATCHED_RELOC_SZ); - f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); - - f_close(&fp); - - sd_unmount(); - gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); - btn_wait(); - - u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); - - void (*sept)() = (void *)pk1t_sept; - - reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); - - // Patch SDRAM init to perform an SVC immediately after second write. - PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; - PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; - // Set SVC handler to jump to sept-primary in IRAM. - PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; - PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - - reconfig_hw_workaround(false, 0); - - (*sept)(); - -error: - EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again."); - display_backlight_brightness(100, 1000); - - btn_wait(); - - return 0; +/* + * 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 . + */ + +#include + +#include "sept.h" +#include "../gfx/di.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../soc/hw_init.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../storage/nx_emmc.h" +#include "../storage/sdmmc.h" +#include "../utils/btn.h" +#include "../utils/types.h" + +#include "../gfx/gfx.h" + +#define PATCHED_RELOC_SZ 0x94 + +#define WB_RST_ADDR 0x40010ED0 +#define WB_RST_SIZE 0x30 + +u8 warmboot_reboot[] = { + 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 + 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 + 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0xFE, 0xFF, 0xFF, 0xEA, // LOOP + 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 + 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 +}; + +#define SEPT_PRI_ADDR 0x4003F000 + +#define SEPT_PK1T_ADDR 0xC0400000 +#define SEPT_PK1T_STACK 0x40008000 +#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) +#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) +#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) +#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) + +extern boot_cfg_t b_cfg; +extern void sd_unmount(); +extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); + +int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) +{ + FIL fp; + + // Copy warmboot reboot code and TSEC fw. + memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); + memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); + *(vu32 *)SEPT_TCSZ_ADDR = tsec_size; + + // Copy sept-primary. + if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) + goto error; + + if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Copy sept-secondary. + if (kb < KB_FIRMWARE_VERSION_810) + { + if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) + if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. + goto error; + } + else + { + if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) + goto error; + } + + if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Save auto boot config to sept payload, if any. + boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); + memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t)); + + tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; + + if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) + goto error; + + f_lseek(&fp, PATCHED_RELOC_SZ); + f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); + + f_close(&fp); + + sd_unmount(); + gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); + btn_wait(); + + u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); + + void (*sept)() = (void *)pk1t_sept; + + reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); + + // Patch SDRAM init to perform an SVC immediately after second write. + PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; + PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; + // Set SVC handler to jump to sept-primary in IRAM. + PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; + PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; + + reconfig_hw_workaround(false, 0); + + (*sept)(); + +error: + EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again."); + display_backlight_brightness(100, 1000); + + btn_wait(); + + return 0; } \ No newline at end of file diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 02a13d7..94477e0 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -1,165 +1,165 @@ -/* - * Copyright (c) 2019 shchmue - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -static const u8 zeros[0x10] = {0}; - -static const u8 keyblob_key_source[][0x10] = { - {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 - {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 - {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 - {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 - {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 - {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 -}; - -static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = { - {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 - {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 - {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 - {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 -}; - -static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = -{ - {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ - {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ - {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ - {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */ - {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */ - {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */ - {0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */ - {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ - {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ - {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ -}; - -//======================================Keys======================================// -// from Package1 -> Secure_Monitor -static const u8 aes_kek_generation_source[0x10] = { - 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_kek_seed_01[0x10] = { - 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_kek_seed_03[0x10] = { - 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; -static const u8 package2_key_source[0x10] = { - 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; -static const u8 titlekek_source[0x10] = { - 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -static const u8 retail_specific_aes_key_source[0x10] = { - 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; - -// from Package1ldr (or Secure_Monitor on 6.2.0) -static const u8 keyblob_mac_key_source[0x10] = { - 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; -static const u8 master_key_source[0x10] = { - 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; -static const u8 per_console_key_source[0x10] = { - 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; -static const u8 per_console_key_source_4x[0x10] = { - 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; - -static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ - {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ - {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ - {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ - {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ - {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ -}; - -static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ - {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ - {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ - {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ - {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */ -}; - -// from SPL -static const u8 aes_key_generation_source[0x10] = { - 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; - -// from FS -static const u8 bis_kek_source[0x10] = { - 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] = { - { - 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, - 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, - { - 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, - 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, - { - 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, - 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} -}; - -static const u8 fs_hashes_sha256[10][0x20] = { - { // header_kek_source - 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, - 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, - { // header_key_source - 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba, - 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, - { // key_area_key_application_source - 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f, - 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, - { // key_area_key_ocean_source - 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b, - 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, - { // key_area_key_system_source - 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e, - 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, - { // save_mac_kek_source - 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A, - 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, - { // save_mac_key_source - 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, - 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, - { // sd_card_kek_source - 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, - 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, - { // sd_card_nca_key_source - 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0, - 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, - { // sd_card_save_key_source - 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A, - 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C} -}; - -static const u8 es_hashes_sha256[3][0x20] = { - { // eticket_rsa_kek - 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73, - 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, - { // eticket_rsa_kekek - 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96, - 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C} -}; - -static const u8 ssl_hashes_sha256[2][0x20] = { - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, - { // ssl_rsa_kek_source_y - 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47, - 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42} +/* + * Copyright (c) 2019 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +static const u8 zeros[0x10] = {0}; + +static const u8 keyblob_key_source[][0x10] = { + {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 + {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 + {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 + {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 + {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 + {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 +}; + +static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = { + {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 + {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 + {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 + {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 +}; + +static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = +{ + {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ + {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ + {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ + {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */ + {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */ + {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */ + {0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */ + {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ + {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ + {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ +}; + +//======================================Keys======================================// +// from Package1 -> Secure_Monitor +static const u8 aes_kek_generation_source[0x10] = { + 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; +static const u8 aes_kek_seed_01[0x10] = { + 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; +static const u8 aes_kek_seed_03[0x10] = { + 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; +static const u8 package2_key_source[0x10] = { + 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; +static const u8 titlekek_source[0x10] = { + 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; +static const u8 retail_specific_aes_key_source[0x10] = { + 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; + +// from Package1ldr (or Secure_Monitor on 6.2.0) +static const u8 keyblob_mac_key_source[0x10] = { + 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; +static const u8 master_key_source[0x10] = { + 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; +static const u8 per_console_key_source[0x10] = { + 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; +static const u8 per_console_key_source_4x[0x10] = { + 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; + +static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ + {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ + {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ +}; + +static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ + {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ + {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ + {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */ +}; + +// from SPL +static const u8 aes_key_generation_source[0x10] = { + 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; + +// from FS +static const u8 bis_kek_source[0x10] = { + 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; +static const u8 bis_key_source[3][0x20] = { + { + 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, + 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, + { + 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, + 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, + { + 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, + 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} +}; + +static const u8 fs_hashes_sha256[10][0x20] = { + { // header_kek_source + 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, + 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, + { // header_key_source + 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba, + 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, + { // key_area_key_application_source + 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f, + 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, + { // key_area_key_ocean_source + 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b, + 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, + { // key_area_key_system_source + 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e, + 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, + { // save_mac_kek_source + 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A, + 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, + { // save_mac_key_source + 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, + 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, + { // sd_card_kek_source + 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, + 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, + { // sd_card_nca_key_source + 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0, + 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, + { // sd_card_save_key_source + 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A, + 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C} +}; + +static const u8 es_hashes_sha256[3][0x20] = { + { // eticket_rsa_kek + 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73, + 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, + { // eticket_rsa_kekek + 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96, + 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, + { // ssl_rsa_kek_source_x + 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, + 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C} +}; + +static const u8 ssl_hashes_sha256[2][0x20] = { + { // ssl_rsa_kek_source_x + 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, + 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, + { // ssl_rsa_kek_source_y + 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47, + 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42} }; \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c index 6c25aec..ca4b9f9 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -342,7 +342,7 @@ get_tsec: ; // Parse eMMC GPT. LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &storage); - + // Find package2 partition. emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); if (!pkg2_part) { diff --git a/source/libs/compr/blz.c b/source/libs/compr/blz.c index ffe78f0..226d011 100644 --- a/source/libs/compr/blz.c +++ b/source/libs/compr/blz.c @@ -32,24 +32,24 @@ const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int com } // From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) +int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) { u32 addl_size = footer->addl_size; u32 header_size = footer->header_size; u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; - + unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size; u32 cmp_ofs = cmp_and_hdr_size - header_size; u32 out_ofs = cmp_and_hdr_size + addl_size; - - while (out_ofs) + + while (out_ofs) { unsigned char control = cmp_start[--cmp_ofs]; - for (unsigned int i=0; i<8; i++) + for (unsigned int i=0; i<8; i++) { - if (control & 0x80) + if (control & 0x80) { - if (cmp_ofs < 2) + if (cmp_ofs < 2) return 0; // Out of bounds. cmp_ofs -= 2; @@ -64,17 +64,17 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const for (unsigned int j = 0; j < seg_size; j++) cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; } - else + else { // Copy directly. - if (cmp_ofs < 1) + if (cmp_ofs < 1) return 0; //out of bounds cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; } control <<= 1; if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done. - return 1; + return 1; } } diff --git a/source/power/max17050.c b/source/power/max17050.c index d34c340..aca452e 100644 --- a/source/power/max17050.c +++ b/source/power/max17050.c @@ -262,7 +262,7 @@ int max17050_fix_configuration() /* Init complete, Clear the POR bit */ //_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR? - // Sets POR, BI, BR. + // Sets POR, BI, BR. _max17050_set_por_bit(0x8801); return 0; diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index 7e2d3af..e214363 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -36,7 +36,7 @@ void max77620_rtc_get_time(rtc_time_t *time) time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; - + if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK) time->hour = (time->hour & 0xF) + 12; diff --git a/source/sec/se.c b/source/sec/se.c index ab9d400..6070400 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -138,7 +138,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr memcpy(block, src, src_size); int res = _se_execute(op, block, 0x10, block, 0x10); memcpy(dst, block, dst_size); - + free(block); return res; } diff --git a/source/sec/tsec.c b/source/sec/tsec.c index 55fb1b4..e07ca83 100644 --- a/source/sec/tsec.c +++ b/source/sec/tsec.c @@ -154,7 +154,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) se = page_alloc(1); memcpy(se, (void *)SE_BASE, 0x1000); smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); - + // Memory controller. mc = page_alloc(1); memcpy(mc, (void *)MC_BASE, 0x1000); @@ -216,7 +216,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) memcpy(tsec_keys, &key, 0x20); memcpy(tsec_ctxt->pkg1, iram, 0x30000); - + smmu_deinit_for_tsec(); // for (int i = 0; i < kidx; i++) diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index d694b32..7cdea95 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -53,9 +53,9 @@ void _config_oscillators() CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE. @@ -187,7 +187,7 @@ void _config_se_brom() if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) { // Bootrom part we skipped. - u32 sbk[4] = { + u32 sbk[4] = { FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), FUSE(FUSE_PRIVATE_KEY2), diff --git a/source/soc/pinmux.h b/source/soc/pinmux.h index 2db4a75..bb4ecb1 100644 --- a/source/soc/pinmux.h +++ b/source/soc/pinmux.h @@ -97,7 +97,7 @@ #define PINMUX_OPEN_DRAIN (1 << 11) #define PINMUX_SCHMT (1 << 12) -#define PINMUX_DRIVE_1X (0 << 13) +#define PINMUX_DRIVE_1X (0 << 13) #define PINMUX_DRIVE_2X (1 << 13) #define PINMUX_DRIVE_3X (2 << 13) #define PINMUX_DRIVE_4X (3 << 13) diff --git a/source/soc/t210.h b/source/soc/t210.h index 2f7fadd..ea83dbc 100644 --- a/source/soc/t210.h +++ b/source/soc/t210.h @@ -156,7 +156,7 @@ #define SYSCTR0_COUNTERID7 0xFDC #define SYSCTR0_COUNTERID8 0xFF0 #define SYSCTR0_COUNTERID9 0xFF4 -#define SYSCTR0_COUNTERID10 0xFF8 +#define SYSCTR0_COUNTERID10 0xFF8 #define SYSCTR0_COUNTERID11 0xFFC /*! TMR registers. */ diff --git a/source/storage/emummc.c b/source/storage/emummc.c index deae70e..a07d9ed 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -182,7 +182,7 @@ int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, v f_close(&fp); return 0; } - + f_close(&fp); return 1; } @@ -227,7 +227,7 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, f_close(&fp); return 0; } - + f_close(&fp); return 1; } diff --git a/source/storage/sdmmc.c b/source/storage/sdmmc.c index 8ec807c..814556d 100644 --- a/source/storage/sdmmc.c +++ b/source/storage/sdmmc.c @@ -1064,7 +1064,7 @@ 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 is_version_1 = 0; - + // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. sdmmc_storage_init_wait_sd(); @@ -1144,7 +1144,7 @@ DPRINTF("[SD] cleared card detect\n"); free(buf); return 0; } - + //gfx_hexdump(0, storage->raw_scr, 8); DPRINTF("[SD] got scr\n"); diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 0c0c2ff..9330eac 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -77,7 +77,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) { pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; sdmmc->regs->pwrcon = pwr; - } + } return 1; } @@ -385,7 +385,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) static void _sdmmc_reset(sdmmc_t *sdmmc) { - sdmmc->regs->swrst |= + sdmmc->regs->swrst |= TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE; _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; @@ -456,7 +456,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) { u16 cmdflags = 0; - + switch (cmd->rsp_type) { case SDMMC_RSP_TYPE_0: @@ -722,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) sdmmc->regs->norintsts = norintsts & mask; return SDMMC_MASKINT_MASKED; } - + return SDMMC_MASKINT_NOERROR; } @@ -767,7 +767,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) if (!res) return 0; - + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_wait_prnsts_type1(sdmmc); @@ -901,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (res) { @@ -943,7 +943,7 @@ static int _sdmmc_config_sdmmc1() gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); - // Check if SD card is inserted. + // Check if SD card is inserted. if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) return 0; @@ -1055,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc) if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); - // Disable SDMMC power. + // Disable SDMMC power. _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. @@ -1134,7 +1134,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); _sdmmc_get_clkcon(sdmmc); msleep(5); - + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; diff --git a/source/utils/dirlist.c b/source/utils/dirlist.c index 8e6f3cc..b4d0169 100644 --- a/source/utils/dirlist.c +++ b/source/utils/dirlist.c @@ -29,7 +29,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile u32 i = 0, j = 0, k = 0; DIR dir; FILINFO fno; - + char *dir_entries = (char *)calloc(max_entries, 256); char *temp = (char *)calloc(1, 256); @@ -79,7 +79,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { for (j = i + 1; j < k; j++) { - if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) { memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1); memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1); diff --git a/source/utils/sprintf.c b/source/utils/sprintf.c index 4dff822..a310251 100644 --- a/source/utils/sprintf.c +++ b/source/utils/sprintf.c @@ -1,123 +1,123 @@ -/* - * Copyright (c) 2019 shchmue - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "sprintf.h" - -#include - -static void _putc(char *buffer, const char c) { - *buffer = c; -} - -static u32 _puts(char *buffer, const char *s) { - u32 count = 0; - for (; *s; s++, count++) - _putc(buffer + count, *s); - return count; -} - -static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) { - char buf[0x121]; - static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - char *p; - int c = fcnt; - - if (base > 36) - return 0; - - p = buf + 0x120; - *p = 0; - do { - c--; - *--p = digits[v % base]; - v /= base; - } while (v); - - if (fill != 0) { - while (c > 0) { - *--p = fill; - c--; - } - } - - return _puts(buffer, p); -} - -u32 sprintf(char *buffer, const char *fmt, ...) { - va_list ap; - int fill, fcnt; - u32 count = 0; - - va_start(ap, fmt); - while(*fmt) { - if (*fmt == '%') { - fmt++; - fill = 0; - fcnt = 0; - if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') { - fcnt = *fmt; - fmt++; - if (*fmt >= '0' && *fmt <= '9') { - fill = fcnt; - fcnt = *fmt - '0'; - fmt++; - } else { - fill = ' '; - fcnt -= '0'; - } - } - switch (*fmt) { - case 'c': - _putc(buffer + count, va_arg(ap, u32)); - count++; - break; - case 's': - count += _puts(buffer + count, va_arg(ap, char *)); - break; - case 'd': - count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt); - break; - case 'p': - case 'P': - case 'x': - case 'X': - count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt); - break; - case '%': - _putc(buffer + count, '%'); - count++; - break; - case '\0': - goto out; - default: - _putc(buffer + count, '%'); - count++; - _putc(buffer + count, *fmt); - count++; - break; - } - } else { - _putc(buffer + count, *fmt); - count++; - } - fmt++; - } - - out: - buffer[count] = 0; - va_end(ap); - return count; +/* + * Copyright (c) 2019 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "sprintf.h" + +#include + +static void _putc(char *buffer, const char c) { + *buffer = c; +} + +static u32 _puts(char *buffer, const char *s) { + u32 count = 0; + for (; *s; s++, count++) + _putc(buffer + count, *s); + return count; +} + +static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) { + char buf[0x121]; + static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return 0; + + p = buf + 0x120; + *p = 0; + do { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) { + while (c > 0) { + *--p = fill; + c--; + } + } + + return _puts(buffer, p); +} + +u32 sprintf(char *buffer, const char *fmt, ...) { + va_list ap; + int fill, fcnt; + u32 count = 0; + + va_start(ap, fmt); + while(*fmt) { + if (*fmt == '%') { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } else { + fill = ' '; + fcnt -= '0'; + } + } + switch (*fmt) { + case 'c': + _putc(buffer + count, va_arg(ap, u32)); + count++; + break; + case 's': + count += _puts(buffer + count, va_arg(ap, char *)); + break; + case 'd': + count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + case 'x': + case 'X': + count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt); + break; + case '%': + _putc(buffer + count, '%'); + count++; + break; + case '\0': + goto out; + default: + _putc(buffer + count, '%'); + count++; + _putc(buffer + count, *fmt); + count++; + break; + } + } else { + _putc(buffer + count, *fmt); + count++; + } + fmt++; + } + + out: + buffer[count] = 0; + va_end(ap); + return count; } \ No newline at end of file diff --git a/source/utils/sprintf.h b/source/utils/sprintf.h index 9a06022..18c36b5 100644 --- a/source/utils/sprintf.h +++ b/source/utils/sprintf.h @@ -1,24 +1,24 @@ -/* - * Copyright (c) 2019 shchmue - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _SPRINTF_H_ -#define _SPRINTF_H_ - -#include "types.h" - -u32 sprintf(char *buffer, const char *fmt, ...); - -#endif +/* + * Copyright (c) 2019 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SPRINTF_H_ +#define _SPRINTF_H_ + +#include "types.h" + +u32 sprintf(char *buffer, const char *fmt, ...); + +#endif diff --git a/source/utils/util.c b/source/utils/util.c index a1dd7cc..a217520 100644 --- a/source/utils/util.c +++ b/source/utils/util.c @@ -88,7 +88,7 @@ void panic(u32 val) TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; - + while (true) usleep(1); } @@ -126,7 +126,7 @@ void power_off() max77620_rtc_stop_alarm(); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); - + while (true) bpmp_halt(); } From 4a205a8720cd70df7c1fb7864b5663fd69ecf1ee Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 17 Sep 2019 10:24:43 -0600 Subject: [PATCH 005/166] Bump version to v1.5.0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 32b528c..0f47b06 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 4 +LPVERSION_MINOR := 5 LPVERSION_BUGFX := 0 ################################################################################ From 035134f36e1e43f1f16544e19f8a33a3d9d1c9ca Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 25 Sep 2019 12:18:08 -0600 Subject: [PATCH 006/166] Add titlekey dumping and Minerva --- common/common_module.h | 39 ++ source/gfx/tui.c | 6 +- source/hos/sept.c | 3 +- source/ianos/ianos.c | 131 ++++++ source/ianos/ianos.h | 34 ++ source/keys/keys.c | 405 +++++++++++++---- source/libs/elfload/elf.h | 589 +++++++++++++++++++++++++ source/libs/elfload/elfarch.h | 49 ++ source/libs/elfload/elfload.c | 324 ++++++++++++++ source/libs/elfload/elfload.h | 127 ++++++ source/libs/elfload/elfreloc_aarch64.c | 84 ++++ source/libs/elfload/elfreloc_arm.c | 66 +++ source/libs/fatfs/diskio.c | 25 +- source/main.c | 19 +- source/mem/minerva.c | 88 ++++ source/mem/minerva.h | 61 +++ source/mem/mtc_table.h | 560 +++++++++++++++++++++++ source/sec/se.c | 63 +++ source/sec/se.h | 3 + source/soc/hw_init.c | 2 + source/storage/sdmmc_driver.c | 6 + source/utils/util.h | 12 + 22 files changed, 2600 insertions(+), 96 deletions(-) create mode 100644 common/common_module.h create mode 100644 source/ianos/ianos.c create mode 100644 source/ianos/ianos.h create mode 100644 source/libs/elfload/elf.h create mode 100644 source/libs/elfload/elfarch.h create mode 100644 source/libs/elfload/elfload.c create mode 100644 source/libs/elfload/elfload.h create mode 100644 source/libs/elfload/elfreloc_aarch64.c create mode 100644 source/libs/elfload/elfreloc_arm.c create mode 100644 source/mem/minerva.c create mode 100644 source/mem/minerva.h create mode 100644 source/mem/mtc_table.h diff --git a/common/common_module.h b/common/common_module.h new file mode 100644 index 0000000..1d3fb89 --- /dev/null +++ b/common/common_module.h @@ -0,0 +1,39 @@ +/* + * Common Module Header + * Copyright (C) 2018 M4xw + * + * 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 . +*/ + +#pragma once +#include +//TODO: Move it to BDK +#include "common_gfx.h" +#include "common_heap.h" + +// Module Callback +typedef void (*cbMainModule_t)(const char *s); +typedef void (*memcpy_t)(void *, void *, size_t); +typedef void (*memset_t)(void *, int, size_t); + +typedef struct _bdkParams_t +{ + gfx_con_t *gfxCon; + gfx_ctxt_t *gfxCtx; + heap_t *sharedHeap; + memcpy_t memcpy; + memset_t memset; +} *bdkParams_t; + +// Module Entrypoint +typedef void (*moduleEntrypoint_t)(void *, bdkParams_t); diff --git a/source/gfx/tui.c b/source/gfx/tui.c index ed2357a..cd3cea6 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -147,13 +147,11 @@ void *tui_do_menu(menu_t *menu) gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); else gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); - // if (menu->ents[cnt].type == MENT_CAPTION) - // gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption); - if (menu->ents[cnt].type != MENT_CHGLINE) { + if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) { if (cnt == idx) gfx_printf(" %s", menu->ents[cnt].caption); else - gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);//gfx_printf(" %s", menu->ents[cnt].caption); + gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption); } if(menu->ents[cnt].type == MENT_MENU) gfx_printf("%k...", 0xFF0099EE); diff --git a/source/hos/sept.c b/source/hos/sept.c index 3ec628e..f991cf9 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -56,6 +56,7 @@ u8 warmboot_reboot[] = { #define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) #define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) +extern u32 color_idx; extern boot_cfg_t b_cfg; extern void sd_unmount(); extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); @@ -115,7 +116,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) f_close(&fp); sd_unmount(); - gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); + gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]); btn_wait(); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); diff --git a/source/ianos/ianos.c b/source/ianos/ianos.c new file mode 100644 index 0000000..18d4165 --- /dev/null +++ b/source/ianos/ianos.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018 M4xw + * 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 . + */ + +#include + +#include "ianos.h" +#include "../utils/types.h" +#include "../libs/elfload/elfload.h" +#include "../../common/common_module.h" +#include "../mem/heap.h" +#include "../gfx/gfx.h" + +#define IRAM_LIB_ADDR 0x4002B000 +#define DRAM_LIB_ADDR 0xE0000000 + +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 *fileBuf = NULL; + +static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) +{ + bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t)); + bdkParameters->gfxCon = &gfx_con; + bdkParameters->gfxCtx = &gfx_ctxt; + bdkParameters->memcpy = (memcpy_t)&memcpy; + bdkParameters->memset = (memset_t)&memset; + bdkParameters->sharedHeap = &_heap; + + entrypoint(moduleConfig, bdkParameters); +} + +static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size) +{ + (void)ctx; + (void)phys; + (void)size; + return (void *)virt; +} + +static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset) +{ + (void)ctx; + + memcpy(dest, fileBuf + offset, numberBytes); + + return true; +} + +//TODO: Support shared libraries. +uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig) +{ + uintptr_t epaddr = 0; + + if (sdmount) + { + if (!sd_mount()) + goto elfLoadFinalOut; + } + + fileBuf = sd_file_read(path, NULL); + + if (sdmount) + sd_unmount(); + + if (!fileBuf) + goto elfLoadFinalOut; + + + el_ctx ctx; + ctx.pread = _ianos_read_cb; + + if (el_init(&ctx)) + goto elfLoadFinalOut; + + // Set our relocated library's buffer. + switch (type & 0xFFFF) + { + case EXEC_ELF: + case AR64_ELF: + elfBuf = (void *)DRAM_LIB_ADDR; + sd_unmount(); + break; + default: + elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default. + } + + if (!elfBuf) + goto elfLoadFinalOut; + + // Load and relocate library. + ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf; + if (el_load(&ctx, _ianos_alloc_cb)) + goto elfFreeOut; + + if (el_relocate(&ctx)) + goto elfFreeOut; + + // Launch. + epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf; + moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr; + + _ianos_call_ep(ep, moduleConfig); + +elfFreeOut: + free(fileBuf); + elfBuf = NULL; + fileBuf = NULL; + +elfLoadFinalOut: + + return epaddr; +} \ No newline at end of file diff --git a/source/ianos/ianos.h b/source/ianos/ianos.h new file mode 100644 index 0000000..74d02c1 --- /dev/null +++ b/source/ianos/ianos.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 M4xw + * 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 . + */ + +#ifndef IANOS_H +#define IANOS_H + +#include "../utils/types.h" + +typedef enum +{ + DRAM_LIB = 0, // DRAM library. + EXEC_ELF = 1, // Executable elf that does not return. + DR64_LIB = 2, // AARCH64 DRAM library. + AR64_ELF = 3, // Executable elf that does not return. + KEEP_IN_RAM = (1 << 31) // Shared library mask. +} elfType_t; + +uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config); + +#endif \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c index ca4b9f9..2af24cd 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -26,6 +26,7 @@ #include "../libs/fatfs/ff.h" #include "../mem/heap.h" #include "../mem/mc.h" +#include "../mem/minerva.h" #include "../mem/sdram.h" #include "../sec/se.h" #include "../sec/se_t210.h" @@ -51,7 +52,8 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename); extern hekate_config h_cfg; -u32 _key_count = 0; +u32 _key_count = 0, _titlekey_count = 0; +u32 color_idx = 0; sdmmc_storage_t storage; emmc_part_t *system_part; u32 start_time, end_time; @@ -59,13 +61,17 @@ u32 start_time, end_time; #define TPRINTF(text) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", end_time - start_time); \ - start_time = get_tmr_us() + start_time = get_tmr_us(); \ + minerva_periodic_training() + #define TPRINTFARGS(text, args...) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", args, end_time - start_time); \ - start_time = get_tmr_us() + start_time = get_tmr_us(); \ + minerva_periodic_training() + #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) -#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer) +#define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) static u8 temp_key[0x10], bis_key[4][0x20] = {0}, @@ -94,27 +100,31 @@ static u8 temp_key[0x10], titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; // key functions -static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; -static void _save_key(const char *name, const void *data, const u32 len, char *outbuf); -static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf); -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; +static void _save_key(const char *name, const void *data, u32 len, char *outbuf); +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); +static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); // nca functions -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); -static void _update_ctr(u8 *ctr, u32 ofs); +static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); +static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); +static void _update_ctr(u8 *ctr, u32 ofs); +// titlekey functions +static bool _test_key_pair(const void *E, const void *D, const void *N); +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); void dump_keys() { - display_backlight_brightness(100, 1000); + display_backlight_brightness(h_cfg.backlight, 1000); gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); + tui_sbar(true); + start_time = get_tmr_us(); u32 begin_time = get_tmr_us(); u32 retries = 0; - u32 color_idx = 0; tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; @@ -141,10 +151,12 @@ void dump_keys() { } } if (!found_tsec_fw) { - EPRINTF("Failed to locate TSEC firmware."); + EPRINTF("Unable to locate TSEC firmware."); goto out_wait; } + minerva_periodic_training(); + tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); tsec_ctxt.pkg1 = pkg1; tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; @@ -177,10 +189,10 @@ void dump_keys() { u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); f_close(&fp); - gfx_printf("%k\nFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); - color_idx += 2; - gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); - color_idx += 2; + gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); + gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); + gfx_printf("\n to /sept/payload.bak\n\n", colors[(color_idx++) % 6]); + gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); sdmmc_storage_end(&storage); if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) goto out_wait; @@ -239,7 +251,8 @@ get_tsec: ; se_aes_key_set(8, master_key[0], 0x10); se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); if (_key_exists(temp_key)) { - EPRINTFARGS("Failed to derive master key. kb = %d", pkg1_id->kb); + EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); + memset(master_key, 0, sizeof(master_key)); } } else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) { // handle sept version differences @@ -257,7 +270,8 @@ get_tsec: ; memcpy(master_key[kb], zeros, 0x10); } if (_key_exists(temp_key)) { - EPRINTF("Failed to derive master key."); + EPRINTF("Unable to derive master key."); + memset(master_key, 0, sizeof(master_key)); } } } @@ -269,6 +283,7 @@ get_tsec: ; se_aes_key_set(8, tsec_keys, 0x10); se_aes_key_set(9, sbk, 0x10); for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) { + minerva_periodic_training(); se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keyblob_key[i], 0x10); @@ -305,7 +320,7 @@ get_tsec: ; /* key = unwrap(source, wrapped_key): key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key */ - + minerva_periodic_training(); u32 key_generation = 0; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { @@ -346,7 +361,7 @@ get_tsec: ; // Find package2 partition. emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); if (!pkg2_part) { - EPRINTF("Failed to locate Package2."); + EPRINTF("Unable to locate Package2."); goto pkg2_done; } @@ -367,6 +382,7 @@ get_tsec: ; nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. + minerva_periodic_training(); pkg2_hdr_t *pkg2_hdr; pkg2_hdr_t hdr; u32 pkg2_kb; @@ -379,14 +395,14 @@ get_tsec: ; break; } if (pkg2_kb == MAX_KEY) { - EPRINTF("Failed to derive Package2 key."); + EPRINTF("Unable to derive Package2 key."); goto pkg2_done; } else if (pkg2_kb != pkg1_id->kb) EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb); pkg2_hdr = pkg2_decrypt(pkg2); if (!pkg2_hdr) { - EPRINTF("Failed to decrypt Package2."); + EPRINTF("Unable to decrypt Package2."); goto pkg2_done; } @@ -406,7 +422,7 @@ get_tsec: ; free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); if (!ki) { - EPRINTF("Failed to parse INI1."); + EPRINTF("Unable to parse INI1."); goto pkg2_done; } @@ -485,6 +501,7 @@ get_tsec: ; u8 temp_hash[0x20]; for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) { + minerva_periodic_training(); se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]); if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) { memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]); @@ -504,11 +521,12 @@ get_tsec: ; i += alignment; } } - pkg2_done: free(pkg2); free(ki); + u8 *rights_ids = NULL, *titlekeys = NULL; + TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { @@ -539,7 +557,6 @@ pkg2_done: se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); } - if (!_key_exists(header_key) || !_key_exists(bis_key[2])) { EPRINTF("Missing FS keys. Skipping ES/SSL keys."); @@ -553,12 +570,12 @@ pkg2_done: system_part = nx_emmc_part_find(&gpt, "SYSTEM"); if (!system_part) { - EPRINTF("Failed to locate System partition."); + EPRINTF("Unable to locate System partition."); goto key_output; } __attribute__ ((aligned (16))) FATFS emmc_fs; if (f_mount(&emmc_fs, "emmc:", 1)) { - EPRINTF("Mount failed."); + EPRINTF("Mount Unable."); goto key_output; } @@ -574,7 +591,7 @@ pkg2_done: u8 *temp_file = NULL; if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); + EPRINTF("Unable to open System:/Contents/registered."); goto dismount; } @@ -583,14 +600,14 @@ pkg2_done: f_closedir(&dir); if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); + EPRINTF("Unable to open System:/Contents/registered."); goto dismount; } path[25] = '/'; start_offset = 0; - while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { + minerva_periodic_training(); memcpy(path + 26, fno.fname, 36); path[62] = 0; if (fno.fattrib & AM_DIR) @@ -711,6 +728,20 @@ pkg2_done: f_closedir(&dir); free(dec_header); + // derive eticket_rsa_kek and ssl_rsa_kek + if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); + } + if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys[1]); + } + if (memcmp(pkg1_id->id, "2016", 4)) { TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]); } else { @@ -718,23 +749,22 @@ pkg2_done: } if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to locate SD seed. Skipping."); - goto dismount; + EPRINTF("Unable to open SD seed vector. Skipping."); + goto get_titlekeys; } // get sd seed verification vector if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { - EPRINTF("Unable to locate SD seed. Skipping."); + EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); - goto dismount; + goto get_titlekeys; } f_close(&fp); if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Failed to open ns_appman save.\nSkipping SD seed."); - goto dismount; + EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); + goto get_titlekeys; } - // locate sd seed u8 read_buf[0x20] = {0}; for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) @@ -748,33 +778,188 @@ pkg2_done: TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); +get_titlekeys: + if (!_key_exists(eticket_rsa_kek)) + goto dismount; + + if (!minerva_cfg) { + gfx_printf("%k Minerva not found!\n This may take up to a minute...\n", colors[(color_idx++) % 6]); + gfx_printf(" For better performance, download Hekate\n and put bootloader/sys/libsys_minerva.bso\n on SD.\n"); + } + gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); + u32 save_x = gfx_con.x, save_y = gfx_con.y; + gfx_printf("\n"); + + u8 null_hash[0x20] = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + + se_aes_key_set(8, bis_key[0] + 0x00, 0x10); + se_aes_key_set(9, bis_key[0] + 0x10, 0x10); + + u32 buf_size = 0x80000; + u8 *buffer = (u8 *)malloc(buf_size); + + u8 keypair[0x230] = {0}; + + emummc_storage_read(&storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); + + se_aes_xts_crypt(9, 8, 0, 0, buffer, buffer, 0x4000, 1); + + se_aes_key_set(8, bis_key[2] + 0x00, 0x10); + se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + + if (*(u32 *)buffer != 0x304C4143) { + EPRINTF("CAL0 magic not found. Check BIS key 0."); + free(buffer); + goto dismount; + } + + se_aes_key_set(2, eticket_rsa_kek, 0x10); + se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); + + u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; + + // Check public exponent is 0x10001 big endian + if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { + EPRINTF("Invalid public exponent."); + free(buffer); + goto dismount; + } + + if (!_test_key_pair(E, D, N)) { + EPRINTF("Invalid keypair. Check eticket_rsa_kek."); + free(buffer); + goto dismount; + } + + se_rsa_key_set(0, N, 0x100, D, 0x100); + + if (f_stat("emmc:/save/80000000000000E1", &fno)) { + EPRINTF("Unable to stat ES save 1. Skipping."); + free(buffer); + goto dismount; + } + u64 total_size = fno.fsize; + if (f_stat("emmc:/save/80000000000000E2", &fno)) { + EPRINTF("Unable to stat ES save 2. Skipping."); + free(buffer); + goto dismount; + } + total_size += fno.fsize; + u32 br; + u64 total_br = 0; + rights_ids = (u8 *)malloc(0x400000); + titlekeys = (u8 *)malloc(0x400000); + u8 M[0x100]; + if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open ES save 1. Skipping."); + free(buffer); + goto dismount; + } + f_lseek(&fp, 0x8000); + u32 pct = 0, last_pct = 0; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + + while (!f_read(&fp, buffer, buf_size, &br)) { + total_br += br; + for (u32 i = 0; i < br; i += 0x4000) { + pct = (u32)((total_br + i) * 100 / total_size); + if (pct > last_pct && pct <= 100) { + last_pct = pct; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + } + for (u32 j = i; j < i + 0x4000; j += 0x400) { + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + u32 k = 0; + bool titlekey_found = false; + for (; k < _titlekey_count; k++) { + if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { + titlekey_found = true; + break; + } + } + if (titlekey_found) + continue; + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); + _titlekey_count++; + } else { + break; + } + } + } + if (br < buf_size) break; + } + + u32 common_titlekey_count = _titlekey_count; + if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open ES save 2. Skipping."); + free(buffer); + goto dismount; + } + f_lseek(&fp, 0x8000); + while (!f_read(&fp, buffer, buf_size, &br)) { + total_br += br; + for (u32 i = 0; i < br; i += 0x4000) { + pct = (u32)((total_br + i) * 100 / total_size); + if (pct > last_pct && pct <= 100) { + last_pct = pct; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + } + for (u32 j = i; j < i + 0x4000; j += 0x400) { + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + u32 k = common_titlekey_count; + bool titlekey_found = false; + for (; k < _titlekey_count; k++) { + if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { + titlekey_found = true; + break; + } + } + if (titlekey_found) + continue; + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + + u8 *titlekey_block = buffer + j + 0x180; + se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); + u8 *salt = M + 1; + u8 *db = M + 0x21; + _mgf1_xor(salt, 0x20, db, 0xdf); + _mgf1_xor(db, 0xdf, salt, 0x20); + if (memcmp(db, null_hash, 0x20)) + continue; + memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); + _titlekey_count++; + } else { + break; + } + } + } + if (br < buf_size) break; + } + free(buffer); + f_close(&fp); + + gfx_con_setpos(0, save_y); + TPRINTFARGS("\n%k ", colors[(color_idx++) % 6]); + gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); + dismount: f_mount(NULL, "emmc:", 1); nx_emmc_gpt_free(&gpt); emummc_storage_end(&storage); - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(8, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, eticket_rsa_kek, es_keys[0]); - } - if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(8, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, ssl_rsa_kek, ssl_keys[1]); - } - key_output: ; - __attribute__ ((aligned (16))) char text_buffer[0x3000] = {0}; + char *text_buffer = (char *)malloc(_titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); SAVE_KEY("bis_kek_source", bis_kek_source, 0x10); - SAVE_KEY_FAMILY("bis_key", bis_key, 4, 0x20); - SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 3, 0x20); + SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20); + SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20); SAVE_KEY("device_key", device_key, 0x10); SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); @@ -782,26 +967,23 @@ key_output: ; SAVE_KEY("header_kek_source", fs_keys[0], 0x10); SAVE_KEY("header_key", header_key, 0x20); SAVE_KEY("header_key_source", fs_keys[1], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10); - SAVE_KEY_FAMILY("keyblob", keyblob, 6, 0x90); - SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 6, 0x10); + SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); + SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); + SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); + SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, MAX_KEY, 0x10); - SAVE_KEY("master_kek_source_06", master_kek_sources[0], 0x10); - SAVE_KEY("master_kek_source_07", master_kek_sources[1], 0x10); - SAVE_KEY("master_kek_source_08", master_kek_sources[2], 0x10); - SAVE_KEY("master_kek_source_09", master_kek_sources[3], 0x10); - SAVE_KEY_FAMILY("master_key", master_key, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_kek", master_kek, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); + SAVE_KEY_FAMILY("master_key", master_key, 0, MAX_KEY, 0x10); SAVE_KEY("master_key_source", master_key_source, 0x10); - SAVE_KEY_FAMILY("package1_key", package1_key, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); + SAVE_KEY_FAMILY("package2_key", package2_key, 0, MAX_KEY, 0x10); SAVE_KEY("package2_key_source", package2_key_source, 0x10); SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); @@ -822,7 +1004,7 @@ key_output: ; SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) @@ -831,10 +1013,10 @@ key_output: ; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; end_time = get_tmr_us(); - gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count); + gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); _key_count = 0; - gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time); - gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1); + gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; @@ -845,17 +1027,36 @@ key_output: ; if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else - EPRINTF("Failed to save keys to SD."); - h_cfg.emummc_force_disable = emummc_load_cfg(); + EPRINTF("Unable to save keys to SD."); + + if (_titlekey_count == 0) + goto out_wait; + memset(text_buffer, 0, _titlekey_count * 68 + 1); + for (u32 i = 0; i < _titlekey_count; i++) { + for (u32 j = 0; j < 0x10; j++) + sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]); + sprintf(&text_buffer[i * 68 + 0x20], " = "); + for (u32 j = 0; j < 0x10; j++) + sprintf(&text_buffer[i * 68 + 0x23 + j * 2], "%02x", titlekeys[i * 0x10 + j]); + sprintf(&text_buffer[i * 68 + 0x43], "\n"); + } + sprintf(&keyfile_path[11], "title.keys"); + if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); + } else + EPRINTF("Unable to save titlekeys to SD."); + free(rights_ids); + free(titlekeys); + free(text_buffer); out_wait: + h_cfg.emummc_force_disable = emummc_load_cfg(); sd_unmount(); gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); - btn_wait(); } -static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) { +static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { if (!_key_exists(data)) return; u32 pos = strlen(outbuf); @@ -866,9 +1067,9 @@ static void _save_key(const char *name, const void *data, const u32 len, char *o _key_count++; } -static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) { +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char temp_name[0x40] = {0}; - for (u32 i = 0; i < num_keys; i++) { + for (u32 i = start_key; i < num_keys + start_key; i++) { sprintf(temp_name, "%s_%02x", name, i); _save_key(temp_name, data + i * len, len, outbuf); } @@ -950,3 +1151,45 @@ static void _update_ctr(u8 *ctr, u32 ofs) { for (u32 i = 0; i < 4; i++, ofs >>= 8) ctr[0x10-i-1] = (u8)(ofs & 0xff); } + +static bool _test_key_pair(const void *E, const void *D, const void *N) { + u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0}; + + // 0xCAFEBABE + X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe; + se_rsa_key_set(0, N, 0x100, D, 0x100); + se_rsa_exp_mod(0, Y, 0x100, X, 0x100); + se_rsa_key_set(0, N, 0x100, E, 4); + se_rsa_exp_mod(0, Z, 0x100, Y, 0x100); + + return !memcmp(X, Z, 0x100); +} + +// _mgf1_xor() was derived from Atmosphère's calculate_mgf1_and_xor +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { + u8 cur_hash[0x20]; + u8 hash_buf[0xe4]; + + u32 hash_buf_size = seed_size + 4; + memcpy(hash_buf, seed, seed_size); + u32 round_num = 0; + + u8 *p_out = (u8 *)masked; + + while (masked_size) { + u32 cur_size = masked_size > 0x20 ? 0x20 : masked_size; + + for (u32 i = 0; i < 4; i++) + hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; + round_num++; + + se_calc_sha256(cur_hash, hash_buf, hash_buf_size); + + for (unsigned int i = 0; i < cur_size; i++) { + *p_out ^= cur_hash[i]; + p_out++; + } + + masked_size -= cur_size; + } +} diff --git a/source/libs/elfload/elf.h b/source/libs/elfload/elf.h new file mode 100644 index 0000000..196cf87 --- /dev/null +++ b/source/libs/elfload/elf.h @@ -0,0 +1,589 @@ +/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */ +/* + * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* imported sys/exec_elf.h from OpenBSD */ + +#ifndef ELF_H +#define ELF_H +#include + +typedef uint8_t Elf_Byte; + +typedef uint32_t Elf32_Addr; /* Unsigned program address */ +typedef uint32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef uint32_t Elf32_Word; /* Unsigned large integer */ +typedef uint16_t Elf32_Half; /* Unsigned medium integer */ + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Shalf; + +#ifdef __alpha__ +typedef int64_t Elf64_Sword; +typedef uint64_t Elf64_Word; +#else +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +#endif + +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Xword; + +typedef uint32_t Elf64_Half; +typedef uint16_t Elf64_Quarter; + +/* + * e_ident[] identification indexes + * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html + */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI ID */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] Operating System/ABI */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Id bytes */ + Elf64_Quarter e_type; /* file type */ + Elf64_Quarter e_machine; /* machine type */ + Elf64_Half e_version; /* version number */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* Program hdr offset */ + Elf64_Off e_shoff; /* Section hdr offset */ + Elf64_Half e_flags; /* Processor flags */ + Elf64_Quarter e_ehsize; /* sizeof ehdr */ + Elf64_Quarter e_phentsize; /* Program header entry size */ + Elf64_Quarter e_phnum; /* Number of program headers */ + Elf64_Quarter e_shentsize; /* Section header entry size */ + Elf64_Quarter e_shnum; /* Number of section headers */ + Elf64_Quarter e_shstrndx; /* String table index */ +} Elf64_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +/* + * Don't know if EM_MIPS_RS4_BE, + * EM_SPARC64, EM_PARISC, + * or EM_PPC are ABI compliant + */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_PPC 20 /* PowerPC */ +#define EM_ARM 40 /* ARM AArch32 */ +#define EM_ALPHA 41 /* DEC ALPHA */ +#define EM_SH 42 /* Hitachi/Renesas Super-H */ +#define EM_SPARCV9 43 /* SPARC version 9 */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_AMD64 62 /* AMD64 architecture */ +#define EM_VAX 75 /* DEC VAX */ +#define EM_AARCH64 183 /* ARM AArch64 */ + +/* Non-standard */ +#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct +{ + Elf32_Word sh_name; /* name - index into section header + * string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Half sh_name; /* section name */ + Elf64_Half sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* virtual address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Half sh_link; /* link to another */ + Elf64_Half sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory alignment */ + Elf64_Xword sh_entsize; /* table entry size */ +} Elf64_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_TLS 0x400 /* thread local storage */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \ + * specific section attributes */ + +/* Symbol Table Entry */ +typedef struct elf32_sym +{ + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Half st_name; /* Symbol name index in str table */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Xword st_value; /* value of symbol */ + Elf64_Xword st_size; /* size of symbol */ +} Elf64_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +#define ELF64_ST_BIND(x) ((x) >> 4) +#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_TLS 6 /* thread local storage */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ +} Elf64_Rel; + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ + Elf64_Sxword r_addend; /* adjustment value */ +} Elf64_Rela; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t)) + +#if defined(__mips64__) && defined(__MIPSEL__) +/* + * The 64-bit MIPS ELF ABI uses a slightly different relocation format + * than the regular ELF ABI: the r_info field is split into several + * pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details). + */ +#undef ELF64_R_SYM +#undef ELF64_R_TYPE +#undef ELF64_R_INFO +#define ELF64_R_TYPE(info) (swap32((info) >> 32)) +#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s)) +#endif /* __mips64__ && __MIPSEL__ */ + +/* Program Header */ +typedef struct +{ + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Half p_type; /* entry type */ + Elf64_Half p_flags; /* flags */ + Elf64_Off p_offset; /* offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* file size */ + Elf64_Xword p_memsz; /* memory size */ + Elf64_Xword p_align; /* memory & file alignment */ +} Elf64_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* thread local storage */ +#define PT_LOOS 0x60000000 /* reserved range for OS */ +#define PT_HIOS 0x6fffffff /* specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ +#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ + +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Xword d_tag; /* controls meaning of d_val */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library \ + * search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ +#define DT_LOOS 0x6000000d /* reserved range for OS */ +#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* some other useful tags */ +#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ +#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ +#define DT_FLAGS_1 0x6ffffffb + +/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONLFAT 0x00002000 + +/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ +#define DT_NUM (DT_JMPREL + 1) + +/* + * Note Definitions + */ +typedef struct +{ + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; +} Elf32_Note; + +typedef struct +{ + Elf64_Half namesz; + Elf64_Half descsz; + Elf64_Half type; +} Elf64_Note; + +#if defined(ELFSIZE) && (ELFSIZE == 32) +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_RelA Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Half Elf32_Half +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_Nhdr Elf32_Nhdr +#define Elf_Note Elf32_Note + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELFCLASS ELFCLASS32 + +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#elif defined(ELFSIZE) && (ELFSIZE == 64) + +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_RelA Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Half Elf64_Half +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_Nhdr Elf64_Nhdr +#define Elf_Note Elf64_Note + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELFCLASS ELFCLASS64 + +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#endif + +#endif diff --git a/source/libs/elfload/elfarch.h b/source/libs/elfload/elfarch.h new file mode 100644 index 0000000..f1cc388 --- /dev/null +++ b/source/libs/elfload/elfarch.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ELFARCH_H +#define ELFARCH_H + +#if defined(__i386__) +#define EM_THIS EM_386 +#define EL_ARCH_USES_REL +#elif defined(__amd64__) +#define EM_THIS EM_AMD64 +#define EL_ARCH_USES_RELA +#elif defined(__arm__) +#define EM_THIS EM_ARM +#define EL_ARCH_USES_REL +#elif defined(__aarch64__) +#define EM_THIS EM_AARCH64 +#define EL_ARCH_USES_RELA +#define EL_ARCH_USES_REL +#else +#error specify your ELF architecture +#endif + +#if defined(__LP64__) || defined(__LLP64__) +#define ELFSIZE 64 +#else +#define ELFSIZE 32 +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define ELFDATATHIS ELFDATA2LSB +#else +#define ELFDATATHIS ELFDATA2MSB +#endif + +#endif diff --git a/source/libs/elfload/elfload.c b/source/libs/elfload/elfload.c new file mode 100644 index 0000000..16f8200 --- /dev/null +++ b/source/libs/elfload/elfload.c @@ -0,0 +1,324 @@ +/* + * Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "elfload.h" + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset) +{ + return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO; +} + +#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize)) +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + for (; *i < ctx->ehdr.e_phnum; (*i)++) + { + if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i)))) + return rv; + + if (phdr->p_type == type) + { + return rv; + } + } + + *i = -1; + return rv; +} + +#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize)) +el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + + for (; *i < ctx->ehdr.e_shnum; (*i)++) + { + if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i)))) + + return rv; + + if (shdr->sh_type == type) + { + return rv; + } + } + + *i = -1; + + return rv; +} + +el_status el_init(el_ctx *ctx) +{ + el_status rv = EL_OK; + if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0))) + return rv; + + /* validate header */ + + if (!IS_ELF(ctx->ehdr)) + return EL_NOTELF; + + if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS) + return EL_WRONGBITS; + + if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS) + return EL_WRONGENDIAN; + + if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT) + return EL_NOTELF; + + if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN) + return EL_NOTEXEC; + + if (ctx->ehdr.e_machine != EM_THIS) + return EL_WRONGARCH; + + if (ctx->ehdr.e_version != EV_CURRENT) + return EL_NOTELF; + + /* load phdrs */ + Elf_Phdr ph; + + /* iterate through, calculate extents */ + ctx->base_load_paddr = ctx->base_load_vaddr = 0; + ctx->align = 1; + ctx->memsz = 0; + + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr phend = ph.p_vaddr + ph.p_memsz; + if (phend > ctx->memsz) + ctx->memsz = phend; + + if (ph.p_align > ctx->align) + ctx->align = ph.p_align; + + i++; + } + + // Program Header + if (ctx->ehdr.e_type == ET_DYN) + { + i = 0; + + if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + + ctx->dynoff = ph.p_offset; + ctx->dynsize = ph.p_filesz; + } + else + { + ctx->dynoff = 0; + ctx->dynsize = 0; + } + + // Section String Table + if (ctx->ehdr.e_type == ET_DYN) + { + i = ctx->ehdr.e_shstrndx - 1; + + if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i))) + return rv; + + // Reset + i = 0; + + if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + } + + return rv; +} + +/* +typedef void* (*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); +*/ + +el_status el_load(el_ctx *ctx, el_alloc_cb alloc) +{ + el_status rv = EL_OK; + + /* address deltas */ + Elf_Addr pdelta = ctx->base_load_paddr; + Elf_Addr vdelta = ctx->base_load_vaddr; + + /* iterate paddrs */ + Elf_Phdr ph; + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr pload = ph.p_paddr + pdelta; + Elf_Addr vload = ph.p_vaddr + vdelta; + + /* allocate mem */ + char *dest = alloc(ctx, pload, vload, ph.p_memsz); + if (!dest) + return EL_ENOMEM; + + EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n", + ph.p_offset, ph.p_vaddr, dest); + + /* read loaded portion */ + if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset))) + return rv; + + /* zero mem-only portion */ + memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz); + + i++; + } + + return rv; +} + +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) +{ + el_status rv = EL_OK; + size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn); + + for (unsigned i = 0; i < ndyn; i++) + { + if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn))) + return rv; + + if (dyn->d_tag == tag) + return EL_OK; + } + + dyn->d_tag = DT_NULL; + return EL_OK; +} + +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type) +{ + el_status rv = EL_OK; + + Elf_Dyn rel, relsz, relent; + + if ((rv = el_finddyn(ctx, &rel, type))) + return rv; + + if ((rv = el_finddyn(ctx, &relsz, type + 1))) + return rv; + + if ((rv = el_finddyn(ctx, &relent, type + 2))) + return rv; + + if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL) + { + ri->entrysize = 0; + ri->tablesize = 0; + ri->tableoff = 0; + } + else + { + ri->tableoff = rel.d_un.d_ptr; + ri->tablesize = relsz.d_un.d_val; + ri->entrysize = relent.d_un.d_val; + } + + return rv; +} + +extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel); +extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela); + +el_status el_relocate(el_ctx *ctx) +{ + el_status rv = EL_OK; + + // not dynamic + if (ctx->ehdr.e_type != ET_DYN) + return EL_OK; + + char *base = (char *)ctx->base_load_paddr; + + el_relocinfo ri; +#ifdef EL_ARCH_USES_REL + if ((rv = el_findrelocs(ctx, &ri, DT_REL))) + return rv; + + if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_Rel)); + return EL_BADREL; + } + + size_t relcnt = ri.tablesize / sizeof(Elf_Rel); + Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff); + for (size_t i = 0; i < relcnt; i++) + { + if ((rv = el_applyrel(ctx, &reltab[i]))) + return rv; + } +#endif + +#ifdef EL_ARCH_USES_RELA + if ((rv = el_findrelocs(ctx, &ri, DT_RELA))) + return rv; + + if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_RelA)); + return EL_BADREL; + } + + size_t relacnt = ri.tablesize / sizeof(Elf_RelA); + Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff); + for (size_t i = 0; i < relacnt; i++) + { + if ((rv = el_applyrela(ctx, &relatab[i]))) + return rv; + } +#endif + +#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA) +#error No relocation type defined! +#endif + + return rv; +} diff --git a/source/libs/elfload/elfload.h b/source/libs/elfload/elfload.h new file mode 100644 index 0000000..3a15dc2 --- /dev/null +++ b/source/libs/elfload/elfload.h @@ -0,0 +1,127 @@ +/* + * Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ELFLOAD_H +#define ELFLOAD_H +#include + +#include "elfarch.h" +#include "elf.h" + +#include "../../utils/types.h" + +#ifdef DEBUG +#include "../../gfx/gfx.h" +#define EL_DEBUG(format, ...) \ + gfx_printf(format __VA_OPT__(, ) __VA_ARGS__) +#else +#define EL_DEBUG(...) \ + do \ + { \ + } while (0) +#endif + +typedef enum +{ + EL_OK = 0, + + EL_EIO, + EL_ENOMEM, + + EL_NOTELF, + EL_WRONGBITS, + EL_WRONGENDIAN, + EL_WRONGARCH, + EL_WRONGOS, + EL_NOTEXEC, + EL_NODYN, + EL_BADREL, + +} el_status; + +typedef struct el_ctx +{ + bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset); + + /* base_load_* -> address we are actually going to load at + */ + Elf_Addr + base_load_paddr, + base_load_vaddr; + + /* size in memory of binary */ + Elf_Addr memsz; + + /* required alignment */ + Elf_Addr align; + + /* ELF header */ + Elf_Ehdr ehdr; + + // Section Header Str Table + Elf_Shdr shstr; + Elf_Shdr symtab; + + /* Offset of dynamic table (0 if not ET_DYN) */ + Elf_Off dynoff; + /* Size of dynamic table (0 if not ET_DYN) */ + Elf_Addr dynsize; +} el_ctx; + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset); + +el_status el_init(el_ctx *ctx); +typedef void *(*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); + +el_status el_load(el_ctx *ctx, el_alloc_cb alloccb); + +/* find the next phdr of type \p type, starting at \p *i. + * On success, returns EL_OK with *i set to the phdr number, and the phdr loaded + * in *phdr. + * + * If the end of the phdrs table was reached, *i is set to -1 and the contents + * of *phdr are undefined + */ +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i); + +/* Relocate the loaded executable */ +el_status el_relocate(el_ctx *ctx); + +/* find a dynamic table entry + * returns the entry on success, dyn->d_tag = DT_NULL on failure + */ +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type); + +typedef struct +{ + Elf_Off tableoff; + Elf_Addr tablesize; + Elf_Addr entrysize; +} el_relocinfo; + +/* find all information regarding relocations of a specific type. + * + * pass DT_REL or DT_RELA for type + * sets ri->entrysize = 0 if not found + */ +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type); + +#endif diff --git a/source/libs/elfload/elfreloc_aarch64.c b/source/libs/elfload/elfreloc_aarch64.c new file mode 100644 index 0000000..bbb0ce4 --- /dev/null +++ b/source/libs/elfload/elfreloc_aarch64.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "elfload.h" + +#if defined(__aarch64__) + +#define R_AARCH64_NONE 0 +#define R_AARCH64_RELATIVE 1027 + +el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p = rel->r_addend + ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p += ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/source/libs/elfload/elfreloc_arm.c b/source/libs/elfload/elfreloc_arm.c new file mode 100644 index 0000000..8b905cb --- /dev/null +++ b/source/libs/elfload/elfreloc_arm.c @@ -0,0 +1,66 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you can do + * whatever you want with this stuff. If we meet some day, and you think this + * stuff is worth it, you can buy me a beer in return. M4xw + * ---------------------------------------------------------------------------- + */ + +#include "elfload.h" + +#if defined(__arm__) + +// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf +#define R_ARM_NONE 0 +#define R_ARM_ABS32 2 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_RELATIVE 23 + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset + uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr + +#if 0 // For later symbol usage + Elf32_Sym *elfSym; + const char *symbolName; + + // We resolve relocs from the originating elf-image + elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym; + int strtab_offset = ctx->shstr.sh_offset; + char *strtab = (char *)buffteg + strtab_offset; + symbolName = strtab + elfSym->st_name; + //EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value); +#endif + + switch (type) + { + case R_ARM_NONE: + EL_DEBUG("R_ARM_NONE\n"); + break; + case R_ARM_JUMP_SLOT: + case R_ARM_ABS32: + case R_ARM_GLOB_DAT: + // Stubbed for later purpose + //*p += elfSym->st_value; // + vaddr from sec + //*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now + break; + case R_ARM_RELATIVE: // Needed for PIE + if (sym) + { + return EL_BADREL; + } + *p += ctx->base_load_vaddr; + break; + + default: + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 97f8336..5f48faa 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -46,7 +46,7 @@ typedef struct { } sector_cache_t; #define MAX_SEC_CACHE_ENTRIES 64 -static sector_cache_t *sector_cache = (sector_cache_t*)0x40022000; +static sector_cache_t *sector_cache; static u32 secindex = 0; DSTATUS disk_status ( @@ -135,7 +135,15 @@ DRESULT disk_read ( switch (pdrv) { case 0: - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + if (sdmmc_storage_read(&sd_storage, sector, count, buf)) + { + memcpy(buff, buf, 512 * count); + return RES_OK; + } + return RES_ERROR; case 1:; __attribute__ ((aligned (16))) static u8 tweak[0x10]; @@ -144,6 +152,10 @@ DRESULT disk_read ( u32 tweak_exp = 0; bool regen_tweak = true, cache_sector = false; + if (secindex == 0) { + sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); + } + u32 s = 0; if (count == 1) { for ( ; s < secindex; s++) { @@ -199,7 +211,14 @@ DRESULT disk_write ( { if (pdrv == 1) return RES_WRPRT; - return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + + if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere. + memcpy(buf, buff, 512 * count); + if (sdmmc_storage_write(&sd_storage, sector, count, buf)) + return RES_OK; + return RES_ERROR; } DRESULT disk_ioctl ( diff --git a/source/main.c b/source/main.c index 3fcdef5..26a84a4 100644 --- a/source/main.c +++ b/source/main.c @@ -24,6 +24,7 @@ #include "gfx/tui.h" #include "libs/fatfs/ff.h" #include "mem/heap.h" +#include "mem/minerva.h" #include "power/max77620.h" #include "rtc/max77620-rtc.h" #include "soc/bpmp.h" @@ -165,18 +166,18 @@ void dump_emunand() } ment_t ment_top[] = { - MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED), MDEF_HANDLER("Dump keys from emuMMC", dump_emunand, COLOR_ORANGE), - MDEF_CAPTION("---------------", COLOR_YELLOW), - MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN), - MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE), - MDEF_HANDLER("Power off", power_off, COLOR_VIOLET), - MDEF_END() + MDEF_CAPTION("---------------", COLOR_YELLOW), + MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN), + MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE), + MDEF_HANDLER("Power off", power_off, COLOR_VIOLET), + MDEF_END() }; menu_t menu_top = { ment_top, NULL, 0, 0 }; -#define IPL_STACK_TOP 0x4003F000 +#define IPL_STACK_TOP 0x90010000//0x4003F000 #define IPL_HEAP_START 0x90020000 extern void pivot_stack(u32 stack_top); @@ -189,6 +190,10 @@ void ipl_main() set_default_configuration(); + sd_mount(); + minerva_init(); + minerva_change_freq(FREQ_1600); + display_init(); u32 *fb = display_init_framebuffer(); gfx_init_ctxt(fb, 720, 1280, 720); diff --git a/source/mem/minerva.c b/source/mem/minerva.c new file mode 100644 index 0000000..2ac8516 --- /dev/null +++ b/source/mem/minerva.c @@ -0,0 +1,88 @@ +/* + * 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 . + */ + +#include +#include + +#include "minerva.h" +#include "../soc/fuse.h" +#include "../utils/util.h" + +#include "../soc/clock.h" +#include "../ianos/ianos.h" +#include "../soc/fuse.h" +#include "../soc/t210.h" + +volatile nyx_storage_t *nyx_str = (nyx_storage_t *)0xED000000; + +void minerva_init() +{ + u32 curr_ram_idx = 0; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + // Set table to ram. + mtc_cfg->mtc_table = NULL; + mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + minerva_cfg = (void *)ep_addr; + + if (!minerva_cfg) + return; + + // Get current frequency + for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) + { + if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc) + break; + } + + mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; + mtc_cfg->rate_to = 204000; + mtc_cfg->train_mode = OP_TRAIN; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = 800000; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = 1600000; + minerva_cfg(mtc_cfg, NULL); +} + +void minerva_change_freq(minerva_freq_t freq) +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (minerva_cfg && (mtc_cfg->rate_from != freq)) + { + mtc_cfg->rate_to = freq; + mtc_cfg->train_mode = OP_SWITCH; + minerva_cfg(mtc_cfg, NULL); + } +} + +void minerva_periodic_training() +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (minerva_cfg && mtc_cfg->rate_from == FREQ_1600) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; + minerva_cfg(mtc_cfg, NULL); + } +} \ No newline at end of file diff --git a/source/mem/minerva.h b/source/mem/minerva.h new file mode 100644 index 0000000..dd71658 --- /dev/null +++ b/source/mem/minerva.h @@ -0,0 +1,61 @@ +/* + * 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 . + */ + +#ifndef _FE_MINERVA_H_ +#define _FE_MINERVA_H_ + +#include "mtc_table.h" +#include "../utils/types.h" + +#define EMC_PERIODIC_TRAIN_MS 100 + +typedef struct +{ + s32 rate_to; + s32 rate_from; + emc_table_t *mtc_table; + u32 table_entries; + emc_table_t *current_emc_table; + u32 train_mode; + u32 sdram_id; + u32 prev_temp; + bool emc_2X_clk_src_is_pllmb; + bool fsp_for_src_freq; + bool train_ram_patterns; +} mtc_config_t; + +enum train_mode_t +{ + OP_SWITCH = 0, + OP_TRAIN = 1, + OP_TRAIN_SWITCH = 2, + OP_PERIODIC_TRAIN = 3, + OP_TEMP_COMP = 4 +}; + +typedef enum +{ + FREQ_204 = 204000, + FREQ_800 = 800000, + FREQ_1600 = 1600000 +} minerva_freq_t; + +void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); +void minerva_init(); +void minerva_change_freq(minerva_freq_t freq); +void minerva_periodic_training(); + +#endif diff --git a/source/mem/mtc_table.h b/source/mem/mtc_table.h new file mode 100644 index 0000000..38a3e2f --- /dev/null +++ b/source/mem/mtc_table.h @@ -0,0 +1,560 @@ +/* + * Minerva Training Cell + * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. + * + * 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 . + */ + +#ifndef _MTC_TABLE_H_ +#define _MTC_TABLE_H_ + +#include "../utils/types.h" + +typedef struct +{ + s32 pll_osc_in; + s32 pll_out; + u32 pll_feedback_div; + u32 pll_input_div; + u32 pll_post_div; +} pllm_clk_config_t; + +typedef struct +{ + u32 emc_rc_idx; + u32 emc_rfc_idx; + u32 emc_rfcpb_idx; + u32 emc_refctrl2_idx; + u32 emc_rfc_slr_idx; + u32 emc_ras_idx; + u32 emc_rp_idx; + u32 emc_r2w_idx; + u32 emc_w2r_idx; + u32 emc_r2p_idx; + u32 emc_w2p_idx; + u32 emc_r2r_idx; + u32 emc_tppd_idx; + u32 emc_ccdmw_idx; + u32 emc_rd_rcd_idx; + u32 emc_wr_rcd_idx; + u32 emc_rrd_idx; + u32 emc_rext_idx; + u32 emc_wext_idx; + u32 emc_wdv_chk_idx; + u32 emc_wdv_idx; + u32 emc_wsv_idx; + u32 emc_wev_idx; + u32 emc_wdv_mask_idx; + u32 emc_ws_duration_idx; + u32 emc_we_duration_idx; + u32 emc_quse_idx; + u32 emc_quse_width_idx; + u32 emc_ibdly_idx; + u32 emc_obdly_idx; + u32 emc_einput_idx; + u32 emc_mrw6_idx; + u32 emc_einput_duration_idx; + u32 emc_puterm_extra_idx; + u32 emc_puterm_width_idx; + u32 emc_qrst_idx; + u32 emc_qsafe_idx; + u32 emc_rdv_idx; + u32 emc_rdv_mask_idx; + u32 emc_rdv_early_idx; + u32 emc_rdv_early_mask_idx; + u32 emc_refresh_idx; + u32 emc_burst_refresh_num_idx; + u32 emc_pre_refresh_req_cnt_idx; + u32 emc_pdex2wr_idx; + u32 emc_pdex2rd_idx; + u32 emc_pchg2pden_idx; + u32 emc_act2pden_idx; + u32 emc_ar2pden_idx; + u32 emc_rw2pden_idx; + u32 emc_cke2pden_idx; + u32 emc_pdex2cke_idx; + u32 emc_pdex2mrr_idx; + u32 emc_txsr_idx; + u32 emc_txsrdll_idx; + u32 emc_tcke_idx; + u32 emc_tckesr_idx; + u32 emc_tpd_idx; + u32 emc_tfaw_idx; + u32 emc_trpab_idx; + u32 emc_tclkstable_idx; + u32 emc_tclkstop_idx; + u32 emc_mrw7_idx; + u32 emc_trefbw_idx; + u32 emc_odt_write_idx; + u32 emc_fbio_cfg5_idx; + u32 emc_fbio_cfg7_idx; + u32 emc_cfg_dig_dll_idx; + u32 emc_cfg_dig_dll_period_idx; + u32 emc_pmacro_ib_rxrt_idx; + u32 emc_cfg_pipe_1_idx; + u32 emc_cfg_pipe_2_idx; + u32 emc_pmacro_quse_ddll_rank0_4_idx; + u32 emc_pmacro_quse_ddll_rank0_5_idx; + u32 emc_pmacro_quse_ddll_rank1_4_idx; + u32 emc_pmacro_quse_ddll_rank1_5_idx; + u32 emc_mrw8_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx; + u32 emc_pmacro_ddll_long_cmd_0_idx; + u32 emc_pmacro_ddll_long_cmd_1_idx; + u32 emc_pmacro_ddll_long_cmd_2_idx; + u32 emc_pmacro_ddll_long_cmd_3_idx; + u32 emc_pmacro_ddll_long_cmd_4_idx; + u32 emc_pmacro_ddll_short_cmd_0_idx; + u32 emc_pmacro_ddll_short_cmd_1_idx; + u32 emc_pmacro_ddll_short_cmd_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx; + u32 emc_txdsrvttgen_idx; + u32 emc_fdpd_ctrl_dq_idx; + u32 emc_fdpd_ctrl_cmd_idx; + u32 emc_fbio_spare_idx; + u32 emc_zcal_interval_idx; + u32 emc_zcal_wait_cnt_idx; + u32 emc_mrs_wait_cnt_idx; + u32 emc_mrs_wait_cnt2_idx; + u32 emc_auto_cal_channel_idx; + u32 emc_dll_cfg_0_idx; + u32 emc_dll_cfg_1_idx; + u32 emc_pmacro_autocal_cfg_common_idx; + u32 emc_pmacro_zctrl_idx; + u32 emc_cfg_idx; + u32 emc_cfg_pipe_idx; + u32 emc_dyn_self_ref_control_idx; + u32 emc_qpop_idx; + u32 emc_dqs_brlshft_0_idx; + u32 emc_dqs_brlshft_1_idx; + u32 emc_cmd_brlshft_2_idx; + u32 emc_cmd_brlshft_3_idx; + u32 emc_pmacro_pad_cfg_ctrl_idx; + u32 emc_pmacro_data_pad_rx_ctrl_idx; + u32 emc_pmacro_cmd_pad_rx_ctrl_idx; + u32 emc_pmacro_data_rx_term_mode_idx; + u32 emc_pmacro_cmd_rx_term_mode_idx; + u32 emc_pmacro_cmd_pad_tx_ctrl_idx; + u32 emc_pmacro_data_pad_tx_ctrl_idx; + u32 emc_pmacro_common_pad_tx_ctrl_idx; + u32 emc_pmacro_vttgen_ctrl_0_idx; + u32 emc_pmacro_vttgen_ctrl_1_idx; + u32 emc_pmacro_vttgen_ctrl_2_idx; + u32 emc_pmacro_brick_ctrl_rfu1_idx; + u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx; + u32 emc_pmacro_brick_ctrl_rfu2_idx; + u32 emc_pmacro_data_brick_ctrl_fdpd_idx; + u32 emc_pmacro_bg_bias_ctrl_0_idx; + u32 emc_cfg_3_idx; + u32 emc_pmacro_tx_pwrd_0_idx; + u32 emc_pmacro_tx_pwrd_1_idx; + u32 emc_pmacro_tx_pwrd_2_idx; + u32 emc_pmacro_tx_pwrd_3_idx; + u32 emc_pmacro_tx_pwrd_4_idx; + u32 emc_pmacro_tx_pwrd_5_idx; + u32 emc_config_sample_delay_idx; + u32 emc_pmacro_tx_sel_clk_src_0_idx; + u32 emc_pmacro_tx_sel_clk_src_1_idx; + u32 emc_pmacro_tx_sel_clk_src_2_idx; + u32 emc_pmacro_tx_sel_clk_src_3_idx; + u32 emc_pmacro_tx_sel_clk_src_4_idx; + u32 emc_pmacro_tx_sel_clk_src_5_idx; + u32 emc_pmacro_ddll_bypass_idx; + u32 emc_pmacro_ddll_pwrd_0_idx; + u32 emc_pmacro_ddll_pwrd_1_idx; + u32 emc_pmacro_ddll_pwrd_2_idx; + u32 emc_pmacro_cmd_ctrl_0_idx; + u32 emc_pmacro_cmd_ctrl_1_idx; + u32 emc_pmacro_cmd_ctrl_2_idx; + u32 emc_tr_timing_0_idx; + u32 emc_tr_dvfs_idx; + u32 emc_tr_ctrl_1_idx; + u32 emc_tr_rdv_idx; + u32 emc_tr_qpop_idx; + u32 emc_tr_rdv_mask_idx; + u32 emc_mrw14_idx; + u32 emc_tr_qsafe_idx; + u32 emc_tr_qrst_idx; + u32 emc_training_ctrl_idx; + u32 emc_training_settle_idx; + u32 emc_training_vref_settle_idx; + u32 emc_training_ca_fine_ctrl_idx; + u32 emc_training_ca_ctrl_misc_idx; + u32 emc_training_ca_ctrl_misc1_idx; + u32 emc_training_ca_vref_ctrl_idx; + u32 emc_training_quse_cors_ctrl_idx; + u32 emc_training_quse_fine_ctrl_idx; + u32 emc_training_quse_ctrl_misc_idx; + u32 emc_training_quse_vref_ctrl_idx; + u32 emc_training_read_fine_ctrl_idx; + u32 emc_training_read_ctrl_misc_idx; + u32 emc_training_read_vref_ctrl_idx; + u32 emc_training_write_fine_ctrl_idx; + u32 emc_training_write_ctrl_misc_idx; + u32 emc_training_write_vref_ctrl_idx; + u32 emc_training_mpc_idx; + u32 emc_mrw15_idx; +} burst_regs_t; + + +typedef struct +{ + u32 burst_regs[221]; + u32 burst_reg_per_ch[8]; + u32 shadow_regs_ca_train[221]; + u32 shadow_regs_quse_train[221]; + u32 shadow_regs_rdwr_train[221]; +} burst_regs_table_t; + +typedef struct +{ + u32 ptfv_dqsosc_movavg_c0d0u0_idx; + u32 ptfv_dqsosc_movavg_c0d0u1_idx; + u32 ptfv_dqsosc_movavg_c0d1u0_idx; + u32 ptfv_dqsosc_movavg_c0d1u1_idx; + u32 ptfv_dqsosc_movavg_c1d0u0_idx; + u32 ptfv_dqsosc_movavg_c1d0u1_idx; + u32 ptfv_dqsosc_movavg_c1d1u0_idx; + u32 ptfv_dqsosc_movavg_c1d1u1_idx; + u32 ptfv_write_samples_idx; + u32 ptfv_dvfs_samples_idx; + u32 ptfv_movavg_weight_idx; + u32 ptfv_config_ctrl_idx; +} ptfv_list_table_t; + +typedef struct +{ + u32 emc0_mrw10_idx; + u32 emc1_mrw10_idx; + u32 emc0_mrw11_idx; + u32 emc1_mrw11_idx; + u32 emc0_mrw12_idx; + u32 emc1_mrw12_idx; + u32 emc0_mrw13_idx; + u32 emc1_mrw13_idx; +} burst_reg_per_ch_t; + +typedef struct +{ + u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx; + u32 emc_pmacro_ib_vref_dqs_0_idx; + u32 emc_pmacro_ib_vref_dqs_1_idx; + u32 emc_pmacro_ib_vref_dq_0_idx; + u32 emc_pmacro_ib_vref_dq_1_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx; + u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx; + u32 emc_pmacro_quse_ddll_rank0_0_idx; + u32 emc_pmacro_quse_ddll_rank0_1_idx; + u32 emc_pmacro_quse_ddll_rank0_2_idx; + u32 emc_pmacro_quse_ddll_rank0_3_idx; + u32 emc_pmacro_quse_ddll_rank1_0_idx; + u32 emc_pmacro_quse_ddll_rank1_1_idx; + u32 emc_pmacro_quse_ddll_rank1_2_idx; + u32 emc_pmacro_quse_ddll_rank1_3_idx; +} trim_regs_t; + +typedef struct +{ + u32 emc_cmd_brlshft_0_idx; + u32 emc_cmd_brlshft_1_idx; + u32 emc0_data_brlshft_0_idx; + u32 emc1_data_brlshft_0_idx; + u32 emc0_data_brlshft_1_idx; + u32 emc1_data_brlshft_1_idx; + u32 emc_quse_brlshft_0_idx; + u32 emc_quse_brlshft_1_idx; + u32 emc_quse_brlshft_2_idx; + u32 emc_quse_brlshft_3_idx; +} trim_perch_regs_t; + +typedef struct +{ + u32 t_rp; + u32 t_fc_lpddr4; + u32 t_rfc; + u32 t_pdex; + u32 rl; +} dram_timings_t; + +typedef struct +{ + u32 emc0_training_opt_dqs_ib_vref_rank0_idx; + u32 emc1_training_opt_dqs_ib_vref_rank0_idx; + u32 emc0_training_opt_dqs_ib_vref_rank1_idx; + u32 emc1_training_opt_dqs_ib_vref_rank1_idx; +} vref_perch_regs_t; + +typedef struct +{ + u32 trim_regs[138]; + u32 trim_perch_regs[10]; + u32 vref_perch_regs[4]; +} trim_regs_table_t; + +typedef struct +{ + u32 rev; + char dvfs_ver[60]; + u32 rate_khz; + u32 min_volt; + u32 gpu_min_volt; + char clock_src[32]; + u32 clk_src_emc; + u32 needs_training; + u32 training_pattern; + u32 trained; + u32 periodic_training; + u32 trained_dram_clktree_c0d0u0; + u32 trained_dram_clktree_c0d0u1; + u32 trained_dram_clktree_c0d1u0; + u32 trained_dram_clktree_c0d1u1; + u32 trained_dram_clktree_c1d0u0; + u32 trained_dram_clktree_c1d0u1; + u32 trained_dram_clktree_c1d1u0; + u32 trained_dram_clktree_c1d1u1; + u32 current_dram_clktree_c0d0u0; + u32 current_dram_clktree_c0d0u1; + u32 current_dram_clktree_c0d1u0; + u32 current_dram_clktree_c0d1u1; + u32 current_dram_clktree_c1d0u0; + u32 current_dram_clktree_c1d0u1; + u32 current_dram_clktree_c1d1u0; + u32 current_dram_clktree_c1d1u1; + u32 run_clocks; + u32 tree_margin; + u32 num_burst; + u32 num_burst_per_ch; + u32 num_trim; + u32 num_trim_per_ch; + u32 num_mc_regs; + u32 num_up_down; + u32 vref_num; + u32 training_mod_num; + u32 dram_timing_num; + + ptfv_list_table_t ptfv_list; + + burst_regs_t burst_regs; + burst_reg_per_ch_t burst_reg_per_ch; + burst_regs_t shadow_regs_ca_train; + burst_regs_t shadow_regs_quse_train; + burst_regs_t shadow_regs_rdwr_train; + trim_regs_t trim_regs; + trim_perch_regs_t trim_perch_regs; + vref_perch_regs_t vref_perch_regs; + dram_timings_t dram_timings; + + u32 training_mod_regs[20]; + u32 save_restore_mod_regs[12]; + u32 burst_mc_regs[33]; + u32 la_scale_regs[24]; + + u32 min_mrs_wait; + u32 emc_mrw; + u32 emc_mrw2; + u32 emc_mrw3; + u32 emc_mrw4; + u32 emc_mrw9; + u32 emc_mrs; + u32 emc_emrs; + u32 emc_emrs2; + u32 emc_auto_cal_config; + u32 emc_auto_cal_config2; + u32 emc_auto_cal_config3; + u32 emc_auto_cal_config4; + u32 emc_auto_cal_config5; + u32 emc_auto_cal_config6; + u32 emc_auto_cal_config7; + u32 emc_auto_cal_config8; + u32 emc_cfg_2; + u32 emc_sel_dpd_ctrl; + u32 emc_fdpd_ctrl_cmd_no_ramp; + u32 dll_clk_src; + u32 clk_out_enb_x_0_clk_enb_emc_dll; + u32 latency; +} emc_table_t; + +#endif \ No newline at end of file diff --git a/source/sec/se.c b/source/sec/se.c index 6070400..fbd0d4c 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -33,6 +33,9 @@ typedef struct _se_ll_t vu32 size; } se_ll_t; +static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT]; +static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT]; + static void _gf256_mul_x(void *block) { u8 *pdata = (u8 *)block; @@ -158,6 +161,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags) SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); } +// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot +void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size) +{ + u32 *data = (u32 *)mod; + for (u32 i = 0; i < mod_size / 4; i++) + { + SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i; + SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]); + } + + data = (u32 *)exp; + for (u32 i = 0; i < exp_size / 4; i++) + { + SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i; + SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]); + } + + _se_rsa_mod_sizes[ks] = mod_size; + _se_rsa_exp_sizes[ks] = exp_size; +} + +// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot +void se_rsa_key_clear(u32 ks) +{ + for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++) + { + SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i; + SE(SE_RSA_KEYTABLE_DATA) = 0; + } + for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++) + { + SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i; + SE(SE_RSA_KEYTABLE_DATA) = 0; + } +} + +// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output +int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + int res; + u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE]; + + for (u32 i = 0; i < src_size; i++) + stack_buf[i] = *((u8 *)src + src_size - i - 1); + + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG); + SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks); + SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1; + SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2; + + res = _se_execute(OP_START, NULL, 0, stack_buf, src_size); + + // Copy output hash. + u32 *dst32 = (u32 *)dst; + for (u32 i = 0; i < dst_size / 4; i++) + dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2))); + + return res; +} + void se_key_acc_ctrl(u32 ks, u32 flags) { if (flags & 0x7F) diff --git a/source/sec/se.h b/source/sec/se.h index 263fe02..434a97a 100644 --- a/source/sec/se.h +++ b/source/sec/se.h @@ -20,6 +20,9 @@ #include "../utils/types.h" void se_rsa_acc_ctrl(u32 rs, u32 flags); +void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size); +void se_rsa_key_clear(u32 ks); +int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); void se_key_acc_ctrl(u32 ks, u32 flags); void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size); diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 7cdea95..e343fd0 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -28,6 +28,7 @@ #include "t210.h" #include "../gfx/di.h" #include "../mem/mc.h" +#include "../mem/minerva.h" #include "../mem/sdram.h" #include "../power/max77620.h" #include "../power/max7762x.h" @@ -309,6 +310,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) // Flush and disable MMU. bpmp_mmu_disable(); bpmp_clk_rate_set(BPMP_CLK_NORMAL); + minerva_change_freq(FREQ_204); // 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. diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 9330eac..96910c8 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -32,6 +32,10 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) +#pragma GCC push_options +#pragma GCC target ("thumb") +#pragma GCC optimize ("Os") + /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -1146,3 +1150,5 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) return 0; } + +#pragma GCC pop_options diff --git a/source/utils/util.h b/source/utils/util.h index 7186263..2eb0899 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -19,6 +19,7 @@ #define _UTIL_H_ #include "types.h" +#include "../mem/minerva.h" #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) @@ -29,6 +30,17 @@ typedef struct _cfg_op_t u32 val; } cfg_op_t; +typedef struct _nyx_storage_t +{ + u32 version; + u32 cfg; + u8 irama[0x8000]; + u8 hekate[0x30000]; + u8 rsvd[0x800000]; + mtc_config_t mtc_cfg; + emc_table_t mtc_table; +} nyx_storage_t; + u32 get_tmr_us(); u32 get_tmr_ms(); u32 get_tmr_s(); From d6105b95e1044a7871fff92938d6c351444e6222 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 27 Sep 2019 16:30:44 -0600 Subject: [PATCH 007/166] Add key generation to menu and fix repeat dump bug --- source/keys/keys.c | 83 ++++++++++++++++++++------------------ source/libs/fatfs/diskio.c | 8 +++- source/main.c | 41 +++++++++++++++++-- 3 files changed, 88 insertions(+), 44 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 2af24cd..d70e642 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -52,6 +52,8 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename); extern hekate_config h_cfg; +extern bool clear_sector_cache; + u32 _key_count = 0, _titlekey_count = 0; u32 color_idx = 0; sdmmc_storage_t storage; @@ -73,39 +75,13 @@ u32 start_time, end_time; #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) #define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) -static u8 temp_key[0x10], - bis_key[4][0x20] = {0}, - device_key[0x10] = {0}, - new_device_key[0x10] = {0}, - sd_seed[0x10] = {0}, - // FS-related keys - fs_keys[10][0x20] = {0}, - header_key[0x20] = {0}, - save_mac_key[0x10] = {0}, - // other sysmodule sources - es_keys[3][0x10] = {0}, - eticket_rsa_kek[0x10] = {0}, - ssl_keys[2][0x10] = {0}, - ssl_rsa_kek[0x10] = {0}, - // keyblob-derived families - keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, - keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; - // key functions static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); // nca functions -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); +static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); static void _update_ctr(u8 *ctr, u32 ofs); // titlekey functions @@ -113,6 +89,32 @@ static bool _test_key_pair(const void *E, const void *D, const void *N); static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); void dump_keys() { + u8 temp_key[0x10], + bis_key[4][0x20] = {0}, + device_key[0x10] = {0}, + new_device_key[0x10] = {0}, + sd_seed[0x10] = {0}, + // FS-related keys + fs_keys[10][0x20] = {0}, + header_key[0x20] = {0}, + save_mac_key[0x10] = {0}, + // other sysmodule sources + es_keys[3][0x10] = {0}, + eticket_rsa_kek[0x10] = {0}, + ssl_keys[0x10] = {0}, + ssl_rsa_kek[0x10] = {0}, + // keyblob-derived families + keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, + keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, + keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, + package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, + // master key-derived families + key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, + master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, + master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, + package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, + titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; + display_backlight_brightness(h_cfg.backlight, 1000); gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); @@ -122,6 +124,10 @@ void dump_keys() { tui_sbar(true); + _key_count = 0; + _titlekey_count = 0; + color_idx = 0; + start_time = get_tmr_us(); u32 begin_time = get_tmr_us(); u32 retries = 0; @@ -575,7 +581,7 @@ pkg2_done: } __attribute__ ((aligned (16))) FATFS emmc_fs; if (f_mount(&emmc_fs, "emmc:", 1)) { - EPRINTF("Mount Unable."); + EPRINTF("Unable to mount system partition."); goto key_output; } @@ -657,7 +663,7 @@ pkg2_done: } hash_index = 0; // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0); + temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0, key_area_key); for (u32 i = 0; i <= 0xb0; ) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { @@ -703,11 +709,11 @@ pkg2_done: } if (!memcmp(pkg1_id->id, "2016", 4)) start_offset = 0x449dc; - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70); + temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { - memcpy(ssl_keys[1], temp_file + i, 0x10); + memcpy(ssl_keys, temp_file + i, 0x10); // only get ssl_rsa_kek_source_x from SSL on 1.0.0 // we get it from ES on every other firmware // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 @@ -735,11 +741,11 @@ pkg2_done: _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); } - if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { + if (_key_exists(ssl_keys) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys[1]); + se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); } if (memcmp(pkg1_id->id, "2016", 4)) { @@ -786,7 +792,7 @@ get_titlekeys: gfx_printf("%k Minerva not found!\n This may take up to a minute...\n", colors[(color_idx++) % 6]); gfx_printf(" For better performance, download Hekate\n and put bootloader/sys/libsys_minerva.bso\n on SD.\n"); } - gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); + gfx_printf("%kTitlekeys... ", colors[color_idx % 6]); u32 save_x = gfx_con.x, save_y = gfx_con.y; gfx_printf("\n"); @@ -949,8 +955,8 @@ get_titlekeys: dismount: f_mount(NULL, "emmc:", 1); + clear_sector_cache = true; nx_emmc_gpt_free(&gpt); - emummc_storage_end(&storage); key_output: ; char *text_buffer = (char *)malloc(_titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); @@ -1003,7 +1009,7 @@ key_output: ; SAVE_KEY("secure_boot_key", sbk, 0x10); SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); - SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10); + SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10); SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10); @@ -1014,7 +1020,6 @@ key_output: ; end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); - _key_count = 0; gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); @@ -1051,7 +1056,7 @@ key_output: ; out_wait: h_cfg.emummc_force_disable = emummc_load_cfg(); - sd_unmount(); + emummc_storage_end(&storage); gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); } @@ -1093,7 +1098,7 @@ static inline u32 _read_le_u32(const void *buffer, u32 offset) { (*(u8*)(buffer + offset + 3) << 0x18); } -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len) { +static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; u8 *temp_file = (u8*)malloc(0x400), diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 5f48faa..e820c6a 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -46,8 +46,9 @@ typedef struct { } sector_cache_t; #define MAX_SEC_CACHE_ENTRIES 64 -static sector_cache_t *sector_cache; +static sector_cache_t *sector_cache = NULL; static u32 secindex = 0; +bool clear_sector_cache = false; DSTATUS disk_status ( BYTE pdrv /* Physical drive number to identify the drive */ @@ -152,8 +153,11 @@ DRESULT disk_read ( u32 tweak_exp = 0; bool regen_tweak = true, cache_sector = false; - if (secindex == 0) { + if (secindex == 0 || clear_sector_cache) { + free(sector_cache); sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); + clear_sector_cache = false; + secindex = 0; } u32 s = 0; diff --git a/source/main.c b/source/main.c index 26a84a4..97a5755 100644 --- a/source/main.c +++ b/source/main.c @@ -22,6 +22,7 @@ #include "gfx/di.h" #include "gfx/gfx.h" #include "gfx/tui.h" +#include "hos/pkg1.h" #include "libs/fatfs/ff.h" #include "mem/heap.h" #include "mem/minerva.h" @@ -30,6 +31,7 @@ #include "soc/bpmp.h" #include "soc/hw_init.h" #include "storage/emummc.h" +#include "storage/nx_emmc.h" #include "storage/sdmmc.h" #include "utils/sprintf.h" #include "utils/util.h" @@ -166,8 +168,8 @@ void dump_emunand() } ment_t ment_top[] = { - MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED), - MDEF_HANDLER("Dump keys from emuMMC", dump_emunand, COLOR_ORANGE), + MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), MDEF_CAPTION("---------------", COLOR_YELLOW), MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN), MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE), @@ -177,7 +179,38 @@ ment_t ment_top[] = { menu_t menu_top = { ment_top, NULL, 0, 0 }; -#define IPL_STACK_TOP 0x90010000//0x4003F000 +void _get_key_generations(char *sysnand_label, char *emunand_label) { + sdmmc_t sdmmc; + sdmmc_storage_t storage; + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + sdmmc_storage_end(&storage); + + if (pkg1_id) + sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + ment_top[0].caption = sysnand_label; + if (h_cfg.emummc_force_disable) { + free(pkg1); + return; + } + + emummc_storage_init_mmc(&storage, &sdmmc); + memset(pkg1, 0, NX_EMMC_BLOCKSIZE); + emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + pkg1_id = pkg1_identify(pkg1); + emummc_storage_end(&storage); + + if (pkg1_id) + sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + free(pkg1); + ment_top[1].caption = emunand_label; +} + +#define IPL_STACK_TOP 0x90010000 #define IPL_HEAP_START 0x90020000 extern void pivot_stack(u32 stack_top); @@ -218,6 +251,8 @@ void ipl_main() ment_top[1].handler = NULL; } + _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); + while (true) tui_do_menu(&menu_top); From 9ceb56f74330f0518d14e3008c869a761ca022d8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 27 Sep 2019 16:31:43 -0600 Subject: [PATCH 008/166] Bump version to v1.6.0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0f47b06..31a0d49 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 5 +LPVERSION_MINOR := 6 LPVERSION_BUGFX := 0 ################################################################################ From 21e8ca62044976c6299f8b5727a873e3c3ebea92 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 29 Sep 2019 23:07:05 -0600 Subject: [PATCH 009/166] Fixed key save buffer non-zero init error --- Makefile | 2 +- source/keys/keys.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 31a0d49..2ed0cb4 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 6 -LPVERSION_BUGFX := 0 +LPVERSION_BUGFX := 1 ################################################################################ diff --git a/source/keys/keys.c b/source/keys/keys.c index d70e642..e75adf3 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -959,7 +959,7 @@ dismount: nx_emmc_gpt_free(&gpt); key_output: ; - char *text_buffer = (char *)malloc(_titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); + char *text_buffer = (char *)calloc(1, _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); From 3b6f3564607699231c54e9eebd5e1c3fbbf9bd53 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 29 Sep 2019 23:12:23 -0600 Subject: [PATCH 010/166] Update readme --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 48e7667..bd13c65 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ Due to changes imposed by firmware 7.0.0, Lockpick homebrew can no longer derive Usage = -* Launch Lockpick_RCM.bin using your favorite payload injector -* Upon completion, keys will be saved to `/switch/prod.keys` on SD +* It is highly recommended, but not required, to place Minerva on SD from the latest [Hekate](https://github.com/CTCaer/hekate/releases) for best performance, especially while dumping titlekeys - the file and path is `/bootloader/sys/libsys_minerva.bso` +* Launch Lockpick_RCM.bin using your favorite payload injector or chainloader +* Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD * If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only) Building @@ -16,8 +17,4 @@ Install [devkitARM](https://devkitpro.org/) and run `make`. Massive Thanks to CTCaer! = -This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor. - -Known Issues -= -* Chainloading from SX will hang immediately due to quirks in their hwinit code, please launch payload directly \ No newline at end of file +This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor. \ No newline at end of file From 0024f049b624bb00f1cd1d6fa77cbcb445588ec6 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 6 Oct 2019 18:41:20 -0600 Subject: [PATCH 011/166] Add new FS keys for LibHac, ff.c -> thumb --- source/hos/pkg1.c | 4 ++-- source/keys/key_sources.inl | 11 ++++++++++- source/keys/keys.c | 33 ++++++++++++++++++--------------- source/libs/fatfs/ff.c | 5 +++++ 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 5e36e05..d00937f 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -33,9 +33,9 @@ static const pkg1_id_t _pkg1_ids[] = { { "20181107105733", 6 }, //6.2.0 { "20181218175730", 7 }, //7.0.0 { "20190208150037", 7 }, //7.0.1 - { "20190314172056", 7 }, //8.0.0 + { "20190314172056", 7 }, //8.0.0 - 8.0.1 { "20190531152432", 8 }, //8.1.0 - { "20190809135709", 9 }, //9.0.0 + { "20190809135709", 9 }, //9.0.0 - 9.0.1 { NULL } //End. }; diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 94477e0..7e2ab81 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -110,7 +110,7 @@ static const u8 bis_key_source[3][0x20] = { 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; -static const u8 fs_hashes_sha256[10][0x20] = { +static const u8 fs_hashes_sha256[13][0x20] = { { // header_kek_source 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, @@ -132,6 +132,15 @@ static const u8 fs_hashes_sha256[10][0x20] = { { // save_mac_key_source 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, + { // save_mac_sd_card_kek_source + 0x60, 0x1a, 0x60, 0xbe, 0x13, 0xf6, 0x3e, 0xda, 0xec, 0xcc, 0x96, 0x7f, 0x27, 0xa3, 0xa3, 0x64, + 0x65, 0xcb, 0xe8, 0xf0, 0x29, 0xf0, 0xc4, 0x14, 0xb2, 0x36, 0x6a, 0x8b, 0x8a, 0x0f, 0x13, 0x00}, + { // save_mac_sd_card_key_source + 0xc2, 0x22, 0x0a, 0x38, 0xb6, 0x87, 0x2b, 0x63, 0xee, 0x77, 0xac, 0x8c, 0x28, 0x24, 0x7a, 0x44, + 0x02, 0xe6, 0xdd, 0x85, 0x24, 0x8b, 0x41, 0x9a, 0x6f, 0x9b, 0x17, 0x93, 0xc0, 0x50, 0x3f, 0x21}, + { // sd_card_custom_storage_key_source + 0x6b, 0x8f, 0xd2, 0x6c, 0x76, 0x5b, 0x7c, 0x67, 0x70, 0x0c, 0x68, 0x54, 0x90, 0x8e, 0xbe, 0x88, + 0x45, 0xb0, 0x55, 0xa6, 0xbb, 0xbb, 0xea, 0x0c, 0x06, 0x3a, 0x85, 0x04, 0x12, 0xd4, 0xca, 0x53}, { // sd_card_kek_source 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, diff --git a/source/keys/keys.c b/source/keys/keys.c index e75adf3..082733d 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -95,7 +95,7 @@ void dump_keys() { new_device_key[0x10] = {0}, sd_seed[0x10] = {0}, // FS-related keys - fs_keys[10][0x20] = {0}, + fs_keys[13][0x20] = {0}, header_key[0x20] = {0}, save_mac_key[0x10] = {0}, // other sysmodule sources @@ -435,9 +435,9 @@ get_tsec: ; pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]); - u8 hash_index = 0, hash_max = 9, hash_order[10], - key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20}; - u32 start_offset = 0, hks_offset_from_end = ki->kip1->sections[2].size_decomp, alignment = 1; + u8 hash_index = 0, hash_max = 11, hash_order[13], + key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; + u32 start_offset = 0, hks_offset_from_end = ki->kip1->sections[2].size_decomp, alignment = 0x10; // the FS keys appear in different orders if (!memcmp(pkg1_id->id, "2016", 4)) { @@ -448,16 +448,13 @@ get_tsec: ; hash_index = 1; start_offset = 0x1b517; hks_offset_from_end = 0x125bc2; - alignment = 0x10; u8 temp[7] = {2, 3, 4, 0, 5, 6, 1}; memcpy(hash_order, temp, 7); } else { // 2.0.0 - 8.0.0 - alignment = 0x40; switch (pkg1_id->kb) { case KB_FIRMWARE_VERSION_100_200: start_offset = 0x1d226; - alignment = 0x10; hks_offset_from_end -= 0x26fe; break; case KB_FIRMWARE_VERSION_300: @@ -475,7 +472,6 @@ get_tsec: ; case KB_FIRMWARE_VERSION_500: start_offset = 0x1f3b4; hks_offset_from_end -= 0x465b; - alignment = 0x20; break; case KB_FIRMWARE_VERSION_600: case KB_FIRMWARE_VERSION_620: @@ -497,11 +493,15 @@ get_tsec: ; } if (pkg1_id->kb <= KB_FIRMWARE_VERSION_500) { - u8 temp[10] = {2, 3, 4, 0, 5, 7, 9, 8, 6, 1}; - memcpy(hash_order, temp, 10); + u8 temp[12] = {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}; + memcpy(hash_order, temp, 12); + } else if (pkg1_id->kb <= KB_FIRMWARE_VERSION_620) { + u8 temp[12] = {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}; + memcpy(hash_order, temp, 12); } else { - u8 temp[10] = {6, 5, 7, 2, 3, 4, 0, 9, 8, 1}; - memcpy(hash_order, temp, 10); + u8 temp[13] = {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}; + memcpy(hash_order, temp, 13); + hash_max = 12; } } @@ -1002,9 +1002,12 @@ key_output: ; SAVE_KEY("save_mac_kek_source", fs_keys[5], 0x10); SAVE_KEY("save_mac_key", save_mac_key, 0x10); SAVE_KEY("save_mac_key_source", fs_keys[6], 0x10); - SAVE_KEY("sd_card_kek_source", fs_keys[7], 0x10); - SAVE_KEY("sd_card_nca_key_source", fs_keys[8], 0x20); - SAVE_KEY("sd_card_save_key_source", fs_keys[9], 0x20); + SAVE_KEY("save_mac_sd_card_kek_source", fs_keys[7], 0x10); + SAVE_KEY("save_mac_sd_card_key_source", fs_keys[8], 0x10); + SAVE_KEY("sd_card_custom_storage_key_source", fs_keys[9], 0x20); + SAVE_KEY("sd_card_kek_source", fs_keys[10], 0x10); + SAVE_KEY("sd_card_nca_key_source", fs_keys[11], 0x20); + SAVE_KEY("sd_card_save_key_source", fs_keys[12], 0x20); SAVE_KEY("sd_seed", sd_seed, 0x10); SAVE_KEY("secure_boot_key", sbk, 0x10); SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index c3e2ab9..6c86e0a 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -40,6 +40,9 @@ #include "diskio.h" /* Declarations of device I/O functions */ #include "../../gfx/gfx.h" +#pragma GCC push_options +#pragma GCC target ("thumb") + #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); //#define EFSPRINTF(...) @@ -6647,3 +6650,5 @@ FRESULT f_setcp ( return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ + +#pragma GCC pop_options From 5d1386cc105bae8ab5a84f17b6711ad119b49641 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 7 Oct 2019 13:18:14 -0600 Subject: [PATCH 012/166] Validate more file I/O calls --- source/keys/keys.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 082733d..bf8b382 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -175,7 +175,8 @@ void dump_keys() { if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { - f_unlink("sd:/sept/payload.bin"); + if (f_unlink("sd:/sept/payload.bin")) + gfx_printf("%kNote: no payload.bin already in /sept\n", colors[(color_idx++) % 6]); f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); } @@ -188,16 +189,27 @@ void dump_keys() { goto get_tsec; } // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) - f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak"); + if (!f_stat("sd:/sept/payload.bin", NULL)) { + if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { + EPRINTF("Unable to backup payload.bin."); + goto out_wait; + } + } // write self to payload.bin to run again when sept finishes - f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE); u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; - f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); + if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { + EPRINTF("Unable to open /sept/payload.bin to write."); + goto out_wait; + } + if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { + EPRINTF("Unable to write self to /sept/payload.bin."); + fclose(&fp); + goto out_wait; + } f_close(&fp); gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); - gfx_printf("\n to /sept/payload.bak\n\n", colors[(color_idx++) % 6]); + gfx_printf("\n to /sept/payload.bak\n\n"); gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); sdmmc_storage_end(&storage); if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) @@ -959,7 +971,8 @@ dismount: nx_emmc_gpt_free(&gpt); key_output: ; - char *text_buffer = (char *)calloc(1, _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); + u32 text_buffer_size = _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1; + char *text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); @@ -1026,7 +1039,10 @@ key_output: ; gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); - f_mkdir("sd:/switch"); + if (f_mkdir("sd:/switch")) { + EPRINTF("Unable to create /switch folder on SD.\nNo keyfiles written."); + goto free_buffers; + } char keyfile_path[30] = "sd:/switch/"; if (!(fuse_read_odm(4) & 3)) sprintf(&keyfile_path[11], "prod.keys"); @@ -1038,8 +1054,8 @@ key_output: ; EPRINTF("Unable to save keys to SD."); if (_titlekey_count == 0) - goto out_wait; - memset(text_buffer, 0, _titlekey_count * 68 + 1); + goto free_buffers; + memset(text_buffer, 0, text_buffer_size); for (u32 i = 0; i < _titlekey_count; i++) { for (u32 j = 0; j < 0x10; j++) sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]); @@ -1053,6 +1069,8 @@ key_output: ; gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else EPRINTF("Unable to save titlekeys to SD."); + +free_buffers: free(rights_ids); free(titlekeys); free(text_buffer); From d890616c33c81515e49b2b872652b27ae7df8e6d Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 15 Oct 2019 10:25:20 -0600 Subject: [PATCH 013/166] Fix function name typo --- source/keys/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index bf8b382..4fb7926 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -203,7 +203,7 @@ void dump_keys() { } if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { EPRINTF("Unable to write self to /sept/payload.bin."); - fclose(&fp); + f_close(&fp); goto out_wait; } f_close(&fp); From d4fa066854fe9798896e95272c376b7530a27d3b Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 15 Oct 2019 10:26:42 -0600 Subject: [PATCH 014/166] Bump version to v1.6.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2ed0cb4..efe3066 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 6 -LPVERSION_BUGFX := 1 +LPVERSION_BUGFX := 2 ################################################################################ From ee1a3e08ae2f7b2a94170ef3735b0e150ccdffd4 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 15 Oct 2019 11:11:47 -0600 Subject: [PATCH 015/166] Fix bad f_mkdir check skipping file save --- Makefile | 2 +- source/keys/keys.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index efe3066..d5245cc 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 6 -LPVERSION_BUGFX := 2 +LPVERSION_BUGFX := 3 ################################################################################ diff --git a/source/keys/keys.c b/source/keys/keys.c index 4fb7926..4a2c8a3 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1039,7 +1039,7 @@ key_output: ; gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); - if (f_mkdir("sd:/switch")) { + if (f_mkdir("sd:/switch") != FR_EXIST) { EPRINTF("Unable to create /switch folder on SD.\nNo keyfiles written."); goto free_buffers; } From 340a25651825e4ed3267dbc9f1ab0124a6a882ae Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 15 Oct 2019 11:14:14 -0600 Subject: [PATCH 016/166] Fix the f_mkdir fix --- source/keys/keys.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 4a2c8a3..7caca15 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1039,7 +1039,9 @@ key_output: ; gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); - if (f_mkdir("sd:/switch") != FR_EXIST) { + FRESULT dir_rc = FR_OK; + dir_rc = f_mkdir("sd:/switch"); + if (dir_rc != FR_EXIST && dir_rc != FR_OK) { EPRINTF("Unable to create /switch folder on SD.\nNo keyfiles written."); goto free_buffers; } From 8c2aa76fd08e61863a3dae27b00c103c5491c4b7 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 21 Oct 2019 11:06:39 -0600 Subject: [PATCH 017/166] v1.6.4: Skip f_mkdir validation altogether --- Makefile | 2 +- source/keys/keys.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d5245cc..7d31ed2 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 6 -LPVERSION_BUGFX := 3 +LPVERSION_BUGFX := 4 ################################################################################ diff --git a/source/keys/keys.c b/source/keys/keys.c index 7caca15..acc81fc 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1039,12 +1039,7 @@ key_output: ; gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); - FRESULT dir_rc = FR_OK; - dir_rc = f_mkdir("sd:/switch"); - if (dir_rc != FR_EXIST && dir_rc != FR_OK) { - EPRINTF("Unable to create /switch folder on SD.\nNo keyfiles written."); - goto free_buffers; - } + f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; if (!(fuse_read_odm(4) & 3)) sprintf(&keyfile_path[11], "prod.keys"); From 3ea82573e0ea7b71b3889b6f5c0faf6bbdb740cc Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 22 Oct 2019 11:15:59 -0600 Subject: [PATCH 018/166] Add wait for KFuse init to prevent wrong TSEC key --- source/soc/kfuse.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ source/soc/kfuse.h | 42 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 source/soc/kfuse.c create mode 100644 source/soc/kfuse.h diff --git a/source/soc/kfuse.c b/source/soc/kfuse.c new file mode 100644 index 0000000..1621215 --- /dev/null +++ b/source/soc/kfuse.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../soc/kfuse.h" +#include "../soc/clock.h" +#include "../soc/t210.h" + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +int kfuse_read(u32 *buf) +{ + int res = 0; + + clock_enable_kfuse(); + + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + ; + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + goto out; + + KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; + for (int i = 0; i < KFUSE_NUM_WORDS; i++) + buf[i] = KFUSE(KFUSE_KEYS); + + res = 1; + +out:; + clock_disable_kfuse(); + return res; +} + +int kfuse_wait_ready() +{ + // Wait for KFUSE to finish init and verification of data. + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + { + usleep(500); + } + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + return 0; + + return 1; +} + +#pragma GCC pop_options diff --git a/source/soc/kfuse.h b/source/soc/kfuse.h new file mode 100644 index 0000000..3824eb8 --- /dev/null +++ b/source/soc/kfuse.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _KFUSE_H_ +#define _KFUSE_H_ + +#include "../utils/types.h" + +#define KFUSE_STATE_SOFTRESET (1 << 31) +#define KFUSE_STATE_STOP (1 << 25) +#define KFUSE_STATE_RESTART (1 << 24) +#define KFUSE_STATE_CRCPASS (1 << 17) +#define KFUSE_STATE_DONE (1 << 16) +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_CURBLOCK_MASK 0x3F + +#define KFUSE_KEYADDR_AUTOINC (1<<16) + +#define KFUSE_STATE 0x80 +#define KFUSE_KEYADDR 0x88 +#define KFUSE_KEYS 0x8C + +#define KFUSE_NUM_WORDS 144 + +int kfuse_read(u32 *buf); +int kfuse_wait_ready(); + +#endif From b5e932755a3b3620b79ad015cbecb7466a70a905 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 22 Oct 2019 11:16:32 -0600 Subject: [PATCH 019/166] Remove wait for button press before reboot to Sept --- source/hos/sept.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/hos/sept.c b/source/hos/sept.c index f991cf9..22814db 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -117,7 +117,6 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) sd_unmount(); gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]); - btn_wait(); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); From eee656bb346a6b501d34e3192be7eb93efa02ee2 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 22 Oct 2019 11:18:05 -0600 Subject: [PATCH 020/166] Add missing file for KFuse fix --- source/soc/clock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/soc/clock.c b/source/soc/clock.c index 73e5fb3..0726748 100644 --- a/source/soc/clock.c +++ b/source/soc/clock.c @@ -15,6 +15,7 @@ */ #include "../soc/clock.h" +#include "../soc/kfuse.h" #include "../soc/t210.h" #include "../utils/util.h" #include "../storage/sdmmc.h" @@ -188,6 +189,7 @@ void clock_enable_kfuse() usleep(10); CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; usleep(20); + kfuse_wait_ready(); } void clock_disable_kfuse() From 76a13c85facc6ce9e567995b1801cc9e06b04304 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 22 Oct 2019 11:22:26 -0600 Subject: [PATCH 021/166] Remove "Os" pragmas, merge hekate changes --- source/libs/fatfs/ff.c | 5 ----- source/libs/fatfs/ffconf.h | 2 +- source/power/max17050.c | 5 ----- source/soc/fuse.h | 19 +++++++++++++++++++ source/soc/kfuse.c | 5 ----- source/storage/sdmmc_driver.c | 24 +++++++++--------------- 6 files changed, 29 insertions(+), 31 deletions(-) diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index 6c86e0a..c3e2ab9 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -40,9 +40,6 @@ #include "diskio.h" /* Declarations of device I/O functions */ #include "../../gfx/gfx.h" -#pragma GCC push_options -#pragma GCC target ("thumb") - #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); //#define EFSPRINTF(...) @@ -6650,5 +6647,3 @@ FRESULT f_setcp ( return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ - -#pragma GCC pop_options diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index 221c909..dc9577e 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -97,7 +97,7 @@ */ -#define FF_USE_LFN 1 +#define FF_USE_LFN 3 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / diff --git a/source/power/max17050.c b/source/power/max17050.c index aca452e..227f76b 100644 --- a/source/power/max17050.c +++ b/source/power/max17050.c @@ -43,9 +43,6 @@ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ -#pragma GCC push_options -#pragma GCC optimize ("Os") - int max17050_get_property(enum MAX17050_reg reg, int *value) { u16 data; @@ -267,5 +264,3 @@ int max17050_fix_configuration() return 0; } - -#pragma GCC pop_options \ No newline at end of file diff --git a/source/soc/fuse.h b/source/soc/fuse.h index 191f18a..0748936 100644 --- a/source/soc/fuse.h +++ b/source/soc/fuse.h @@ -37,12 +37,31 @@ #define FUSE_WRITE_ACCESS_SW 0x30 #define FUSE_PWR_GOOD_SW 0x34 #define FUSE_SKU_INFO 0x110 +#define FUSE_CPU_SPEEDO_0_CALIB 0x114 +#define FUSE_CPU_IDDQ_CALIB 0x118 +#define FUSE_OPT_FT_REV 0x128 +#define FUSE_CPU_SPEEDO_1_CALIB 0x12C +#define FUSE_CPU_SPEEDO_2_CALIB 0x130 +#define FUSE_SOC_SPEEDO_0_CALIB 0x134 +#define FUSE_SOC_SPEEDO_1_CALIB 0x138 +#define FUSE_SOC_SPEEDO_2_CALIB 0x13C +#define FUSE_SOC_IDDQ_CALIB 0x140 +#define FUSE_OPT_CP_REV 0x190 #define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c #define FUSE_PRIVATE_KEY0 0x1A4 #define FUSE_PRIVATE_KEY1 0x1A8 #define FUSE_PRIVATE_KEY2 0x1AC #define FUSE_PRIVATE_KEY3 0x1B0 +#define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_RESERVED_SW 0x1C0 +#define FUSE_OPT_VENDOR_CODE 0x200 +#define FUSE_OPT_FAB_CODE 0x204 +#define FUSE_OPT_LOT_CODE_0 0x208 +#define FUSE_OPT_LOT_CODE_1 0x20C +#define FUSE_OPT_WAFER_ID 0x210 +#define FUSE_OPT_X_COORDINATE 0x214 +#define FUSE_OPT_Y_COORDINATE 0x218 +#define FUSE_GPU_IDDQ_CALIB 0x228 /*! Fuse commands. */ #define FUSE_READ 0x1 diff --git a/source/soc/kfuse.c b/source/soc/kfuse.c index 1621215..2f9e5de 100644 --- a/source/soc/kfuse.c +++ b/source/soc/kfuse.c @@ -18,9 +18,6 @@ #include "../soc/clock.h" #include "../soc/t210.h" -#pragma GCC push_options -#pragma GCC optimize ("Os") - int kfuse_read(u32 *buf) { int res = 0; @@ -57,5 +54,3 @@ int kfuse_wait_ready() return 1; } - -#pragma GCC pop_options diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 96910c8..0c0c2ff 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -32,10 +32,6 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -#pragma GCC push_options -#pragma GCC target ("thumb") -#pragma GCC optimize ("Os") - /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -81,7 +77,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) { pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; sdmmc->regs->pwrcon = pwr; - } + } return 1; } @@ -389,7 +385,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) static void _sdmmc_reset(sdmmc_t *sdmmc) { - sdmmc->regs->swrst |= + sdmmc->regs->swrst |= TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE; _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; @@ -460,7 +456,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) { u16 cmdflags = 0; - + switch (cmd->rsp_type) { case SDMMC_RSP_TYPE_0: @@ -726,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) sdmmc->regs->norintsts = norintsts & mask; return SDMMC_MASKINT_MASKED; } - + return SDMMC_MASKINT_NOERROR; } @@ -771,7 +767,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) if (!res) return 0; - + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_wait_prnsts_type1(sdmmc); @@ -905,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (res) { @@ -947,7 +943,7 @@ static int _sdmmc_config_sdmmc1() gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); - // Check if SD card is inserted. + // Check if SD card is inserted. if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) return 0; @@ -1059,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc) if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); - // Disable SDMMC power. + // Disable SDMMC power. _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. @@ -1138,7 +1134,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); _sdmmc_get_clkcon(sdmmc); msleep(5); - + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -1150,5 +1146,3 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) return 0; } - -#pragma GCC pop_options From 28f419007638ac79941e9925ab0f6274574f7ca0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 22 Oct 2019 11:22:55 -0600 Subject: [PATCH 022/166] Compile as Thumb to reduce binary size --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d31ed2..6c33bb3 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) From e5849e3ab25304048e0d6fa283faaa6b706c4bcf Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 10:05:57 -0600 Subject: [PATCH 023/166] Remove invalid free for this use case --- source/hos/pkg2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index e745cbc..301fd4e 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -139,7 +139,6 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) memcpy(newKip, &hdr, sizeof(hdr)); newKipSize = dstDataPtr-(unsigned char*)(newKip); - free(ki->kip1); ki->kip1 = newKip; ki->size = newKipSize; From b468026540486ed70a9ddb71001a7154f7d29546 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:41:30 -0600 Subject: [PATCH 024/166] heap: Prevent node chain collapse on free --- source/mem/heap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/mem/heap.c b/source/mem/heap.c index 4971d8a..fd46c16 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -56,6 +56,7 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment) node->used = 1; new->used = 0; new->next = node->next; + new->next->prev = new; new->prev = node; node->next = new; From 2d4ffd2965d67f08ce201102837db1f43400b21e Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:43:11 -0600 Subject: [PATCH 025/166] diskio: Alloc xts enc, don't realloc sector cache --- source/libs/fatfs/diskio.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index e820c6a..75a1c1e 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -107,7 +107,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe pdst += 0x10; } - se_aes_crypt_ecb(ks2, 0, dst, secsize, src, secsize); + se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize); pdst = (u8 *)dst; @@ -150,12 +150,11 @@ DRESULT disk_read ( __attribute__ ((aligned (16))) static u8 tweak[0x10]; __attribute__ ((aligned (16))) static u64 prev_cluster = -1; __attribute__ ((aligned (16))) static u32 prev_sector = 0; - u32 tweak_exp = 0; - bool regen_tweak = true, cache_sector = false; + bool needs_cache_sector = false; if (secindex == 0 || clear_sector_cache) { - free(sector_cache); - sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); + if (!sector_cache) + sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); clear_sector_cache = false; secindex = 0; } @@ -176,12 +175,14 @@ DRESULT disk_read ( if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) { sector_cache[s].sector = sector; sector_cache[s].visit_count++; - cache_sector = true; + needs_cache_sector = true; secindex++; } } if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) { + u32 tweak_exp = 0; + bool regen_tweak = true; if (prev_cluster != sector / 0x20) { // sector in different cluster than last read prev_cluster = sector / 0x20; tweak_exp = sector % 0x20; @@ -194,7 +195,7 @@ DRESULT disk_read ( // fatfs will never pull more than a cluster _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200); - if (cache_sector) { + if (needs_cache_sector) { memcpy(sector_cache[s].cached_sector, buff, 0x200); memcpy(sector_cache[s].tweak, tweak, 0x10); } From 472aa1665eb82f092d0fdc3703f0d553f26cdc5b Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:44:51 -0600 Subject: [PATCH 026/166] sept: Prevent memory leak --- source/hos/sept.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/hos/sept.c b/source/hos/sept.c index 22814db..1858533 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -107,8 +107,10 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) + if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) { + free(tmp_cfg); goto error; + } f_lseek(&fp, PATCHED_RELOC_SZ); f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); From d946ade94b8ee1eced52b6bd657a5d742e0c440b Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:46:10 -0600 Subject: [PATCH 027/166] kfuse: Fix missing include --- source/soc/kfuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/soc/kfuse.c b/source/soc/kfuse.c index 2f9e5de..52f188f 100644 --- a/source/soc/kfuse.c +++ b/source/soc/kfuse.c @@ -17,6 +17,7 @@ #include "../soc/kfuse.h" #include "../soc/clock.h" #include "../soc/t210.h" +#include "../utils/util.h" int kfuse_read(u32 *buf) { From 535a2d97f2b9f131362cabd21436f11d827bebee Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:54:57 -0600 Subject: [PATCH 028/166] keys: Validate storage init --- source/keys/keys.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index acc81fc..0a6ca1a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -135,7 +135,10 @@ void dump_keys() { tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; - emummc_storage_init_mmc(&storage, &sdmmc); + if (!emummc_storage_init_mmc(&storage, &sdmmc)) { + EPRINTF("Unable to init MMC."); + goto out_wait; + } TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); // Read package1. From 86f2a63fb7a5e6c9e2c964aad347cdcca5f19d6e Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:56:06 -0600 Subject: [PATCH 029/166] keys: Fix failure to free decompressed kip1 --- source/keys/keys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/keys/keys.c b/source/keys/keys.c index 0a6ca1a..250a502 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -543,6 +543,7 @@ get_tsec: ; } } pkg2_done: + free(ki->kip1); free(pkg2); free(ki); From dbc86a66997187c2fd83cfb96447dc60a033f4d8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:57:59 -0600 Subject: [PATCH 030/166] keys: Ensure SD mount before writing key buffer --- source/keys/keys.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 250a502..e412ecd 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -975,8 +975,13 @@ dismount: nx_emmc_gpt_free(&gpt); key_output: ; + char *text_buffer = NULL; + if (!sd_mount()) { + EPRINTF("Unable to mount SD."); + goto free_buffers; + } u32 text_buffer_size = _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1; - char *text_buffer = (char *)calloc(1, text_buffer_size); + text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); @@ -1049,7 +1054,7 @@ key_output: ; sprintf(&keyfile_path[11], "prod.keys"); else sprintf(&keyfile_path[11], "dev.keys"); - if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else EPRINTF("Unable to save keys to SD."); @@ -1066,7 +1071,7 @@ key_output: ; sprintf(&text_buffer[i * 68 + 0x43], "\n"); } sprintf(&keyfile_path[11], "title.keys"); - if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else EPRINTF("Unable to save titlekeys to SD."); From a5bb071927dd983a63c3c3a33a031b33c81e13ba Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 11:59:34 -0600 Subject: [PATCH 031/166] keys: Fix potential memory leak in _nca_process --- source/keys/keys.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index e412ecd..84ca01a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1130,8 +1130,10 @@ static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 l u8 *temp_file = (u8*)malloc(0x400), ctr[0x10] = {0}; - if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400) + if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400) { + free(temp_file); return NULL; + } se_aes_xts_crypt(hk_ks1, hk_ks2, 0, 1, temp_file, temp_file, 0x200, 2); // both 1.x and 2.x use master_key_00 temp_file[0x20] -= temp_file[0x20] ? 1 : 0; From 5f100fef8a7bb14e013f1246f0e269e1a56c9615 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 12:04:03 -0600 Subject: [PATCH 032/166] nx_emmc: Fix nested loop with same variable --- source/storage/nx_emmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index 8e0fb63..8f03848 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -37,8 +37,8 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) part->attrs = ent->attrs; //HACK - for (u32 i = 0; i < 36; i++) - part->name[i] = ent->name[i]; + for (u32 j = 0; j < 36; j++) + part->name[j] = ent->name[j]; part->name[36] = 0; list_append(gpt, &part->link); From 5d44ef0af68865624e73428a200e7ff04ec6aa63 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 21:48:29 -0600 Subject: [PATCH 033/166] se: Hardcode internal se vars, add HMAC-SHA256 --- source/sec/se.c | 54 ++++++++++++++++++++++++++++++++++++-------- source/sec/se.h | 1 + source/sec/se_t210.h | 4 ++-- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/source/sec/se.c b/source/sec/se.c index fbd0d4c..bf76e16 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -94,17 +94,15 @@ static int _se_wait() static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) { - se_ll_t *ll_dst = NULL, *ll_src = NULL; + se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0; if (dst) { - ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_dst, (u32)dst, dst_size); } if (src) { - ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_src, (u32)src, src_size); } @@ -120,11 +118,6 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); - if (src) - free(ll_src); - if (dst) - free(ll_dst); - return res; } @@ -428,7 +421,7 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) int res; // Setup config for SHA256, size = BITS(src_size). SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE; + SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_ENABLE; SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3); SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0; SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0; @@ -448,3 +441,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) return res; } + +int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) { + int res = 0; + u8 *secret = (u8 *)malloc(0x40); + u8 *ipad = (u8 *)malloc(0x40 + src_size); + u8 *opad = (u8 *)malloc(0x60); + + if (key_size > 0x40) + { + if (!se_calc_sha256(secret, key, key_size)) + goto out; + memset(secret + 0x20, 0, 0x20); + } + else + { + memcpy(secret, key, key_size); + memset(secret + key_size, 0, 0x40 - key_size); + } + + u32 *secret32 = (u32 *)secret; + u32 *ipad32 = (u32 *)ipad; + u32 *opad32 = (u32 *)opad; + for (u32 i = 0; i < 0x10; i++) + { + ipad32[i] = secret32[i] ^ 0x36363636; + opad32[i] = secret32[i] ^ 0x5C5C5C5C; + } + + memcpy(ipad + 0x40, src, src_size); + if (!se_calc_sha256(dst, ipad, 0x40 + src_size)) + goto out; + memcpy(opad + 0x40, dst, 0x20); + if (!se_calc_sha256(dst, opad, 0x60)) + goto out; + + res = 1; + +out:; + free(secret); + free(ipad); + free(opad); + return res; +} diff --git a/source/sec/se.h b/source/sec/se.h index 434a97a..0d517c7 100644 --- a/source/sec/se.h +++ b/source/sec/se.h @@ -35,5 +35,6 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size); +int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); #endif diff --git a/source/sec/se_t210.h b/source/sec/se_t210.h index 760527d..7d93099 100644 --- a/source/sec/se_t210.h +++ b/source/sec/se_t210.h @@ -231,8 +231,8 @@ #define SE_SPARE_0_REG_OFFSET 0x80c #define SE_SHA_CONFIG_REG_OFFSET 0x200 -#define SHA_DISABLE 0 -#define SHA_ENABLE 1 +#define SHA_INIT_DISABLE 0 +#define SHA_INIT_ENABLE 1 #define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204 #define SE_SHA_MSG_LEFT_REG_OFFSET 0x214 From 1feb83f1dc1f7e95b850c6334a22b98bde3ba431 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 25 Oct 2019 22:01:23 -0600 Subject: [PATCH 034/166] heap: Fix calloc memset, end node max size on free --- source/mem/heap.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source/mem/heap.c b/source/mem/heap.c index fd46c16..5efdbc2 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -83,7 +83,7 @@ static void _heap_free(heap_t *heap, u32 addr) hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); node->used = 0; node = heap->first; - while (node) + while (1) { if (!node->used) { @@ -95,7 +95,14 @@ static void _heap_free(heap_t *heap, u32 addr) node->next->prev = node->prev; } } - node = node->next; + if (node->next) + node = node->next; + else + { + node->size = -1; + break; + } + } } @@ -114,7 +121,7 @@ void *malloc(u32 size) void *calloc(u32 num, u32 size) { void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t)); - memset(res, 0, num * size); + memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); return res; } From 1c82665901c4da7306547378142efcf62f8f927d Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 26 Oct 2019 20:29:36 -0600 Subject: [PATCH 035/166] Parse ES saves right, vastly improve titlekey time --- source/keys/keys.c | 209 +++++++----- source/keys/save.c | 821 +++++++++++++++++++++++++++++++++++++++++++++ source/keys/save.h | 489 +++++++++++++++++++++++++++ 3 files changed, 1439 insertions(+), 80 deletions(-) create mode 100644 source/keys/save.c create mode 100644 source/keys/save.h diff --git a/source/keys/keys.c b/source/keys/keys.c index 84ca01a..ae7dfe1 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -43,6 +43,7 @@ #include "../utils/util.h" #include "key_sources.inl" +#include "save.h" #include @@ -115,6 +116,8 @@ void dump_keys() { package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; + sd_mount(); + display_backlight_brightness(h_cfg.backlight, 1000); gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); @@ -604,6 +607,8 @@ pkg2_done: DIR dir; FILINFO fno; FIL fp; + save_ctx_t *save_ctx = NULL; + // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient u8 *dec_header = (u8*)malloc(0x600); char path[100] = "emmc:/Contents/registered"; @@ -782,6 +787,7 @@ pkg2_done: } f_close(&fp); + // this file is so small that parsing the savedata properly would take longer if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); goto get_titlekeys; @@ -804,13 +810,9 @@ get_titlekeys: if (!_key_exists(eticket_rsa_kek)) goto dismount; - if (!minerva_cfg) { - gfx_printf("%k Minerva not found!\n This may take up to a minute...\n", colors[(color_idx++) % 6]); - gfx_printf(" For better performance, download Hekate\n and put bootloader/sys/libsys_minerva.bso\n on SD.\n"); - } - gfx_printf("%kTitlekeys... ", colors[color_idx % 6]); + gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); u32 save_x = gfx_con.x, save_y = gfx_con.y; - gfx_printf("\n"); + gfx_printf("\n%kCommon... ", colors[color_idx % 6]); u8 null_hash[0x20] = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, @@ -819,7 +821,7 @@ get_titlekeys: se_aes_key_set(8, bis_key[0] + 0x00, 0x10); se_aes_key_set(9, bis_key[0] + 0x10, 0x10); - u32 buf_size = 0x80000; + u32 buf_size = 0x4000; u8 *buffer = (u8 *)malloc(buf_size); u8 keypair[0x230] = {0}; @@ -857,63 +859,83 @@ get_titlekeys: se_rsa_key_set(0, N, 0x100, D, 0x100); - if (f_stat("emmc:/save/80000000000000E1", &fno)) { - EPRINTF("Unable to stat ES save 1. Skipping."); - free(buffer); - goto dismount; - } - u64 total_size = fno.fsize; - if (f_stat("emmc:/save/80000000000000E2", &fno)) { - EPRINTF("Unable to stat ES save 2. Skipping."); - free(buffer); - goto dismount; - } - total_size += fno.fsize; - u32 br; + u32 br = buf_size; + u32 file_tkey_count = 0; u64 total_br = 0; - rights_ids = (u8 *)malloc(0x400000); - titlekeys = (u8 *)malloc(0x400000); + rights_ids = (u8 *)malloc(0x40000); + titlekeys = (u8 *)malloc(0x40000); + save_ctx = calloc(1, sizeof(save_ctx_t)); u8 M[0x100]; if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open ES save 1. Skipping."); free(buffer); goto dismount; } - f_lseek(&fp, 0x8000); + u32 pct = 0, last_pct = 0; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); - while (!f_read(&fp, buffer, buf_size, &br)) { + save_ctx->file = &fp; + save_ctx->tool_ctx.action = 0; + memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); + save_process(save_ctx); + + char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; + char ticket_list_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket_list.bin"; + allocation_table_storage_ctx_t fat_storage; + save_fs_list_entry_t entry = {0, "", {0}, 0}; + if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + EPRINTF("Unable to locate ticket_list.bin in e1."); + goto dismount; + } + save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); + while (br == buf_size && total_br < entry.value.save_file_info.length) { + br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); + if (buffer[0] == 0) break; total_br += br; - for (u32 i = 0; i < br; i += 0x4000) { - pct = (u32)((total_br + i) * 100 / total_size); + minerva_periodic_training(); + for (u32 j = 0; j < buf_size; j += 0x20) { + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + file_tkey_count++; + } + } + if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + EPRINTF("Unable to locate ticket.bin in e1."); + goto dismount; + } + save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); + total_br = 0; + while (br == buf_size && total_br < entry.value.save_file_info.length) { + br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); + if (buffer[0] == 0) break; + total_br += br; + for (u32 j = 0; j < buf_size; j += 0x400) { + pct = _titlekey_count * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { last_pct = pct; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); } - for (u32 j = i; j < i + 0x4000; j += 0x400) { - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - u32 k = 0; - bool titlekey_found = false; - for (; k < _titlekey_count; k++) { - if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { - titlekey_found = true; - break; - } - } - if (titlekey_found) - continue; - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); - _titlekey_count++; - } else { - break; - } + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); + _titlekey_count++; + } else { + break; } } - if (br < buf_size) break; } + tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); + f_close(&fp); + save_free_contexts(save_ctx); + memset(save_ctx, 0, sizeof(save_ctx_t)); + memset(&fat_storage, 0, sizeof(allocation_table_storage_ctx_t)); + + gfx_con_setpos(0, save_y); + TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); + save_x = gfx_con.x + 16 * 17; + save_y = gfx_con.y; + gfx_printf("\n%kPersonalized... ", colors[color_idx % 6]); u32 common_titlekey_count = _titlekey_count; if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { @@ -921,55 +943,82 @@ get_titlekeys: free(buffer); goto dismount; } - f_lseek(&fp, 0x8000); - while (!f_read(&fp, buffer, buf_size, &br)) { + + save_ctx->file = &fp; + save_ctx->tool_ctx.action = 0; + memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); + save_process(save_ctx); + + if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + EPRINTF("Unable to locate ticket_list.bin in e2."); + goto dismount; + } + save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); + + total_br = 0; + file_tkey_count = 0; + while (br == buf_size && total_br < entry.value.save_file_info.length) { + br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); + if (buffer[0] == 0) break; total_br += br; - for (u32 i = 0; i < br; i += 0x4000) { - pct = (u32)((total_br + i) * 100 / total_size); + minerva_periodic_training(); + for (u32 j = 0; j < buf_size; j += 0x20) { + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + file_tkey_count++; + } + } + if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + EPRINTF("Unable to locate ticket.bin in e2."); + goto dismount; + } + + save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); + + total_br = 0; + pct = 0; + last_pct = 0; + while (br == buf_size && total_br < entry.value.save_file_info.length) { + br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); + if (buffer[0] == 0) break; + total_br += br; + for (u32 j = 0; j < buf_size; j += 0x400) { + pct = (_titlekey_count - common_titlekey_count) * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { last_pct = pct; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); } - for (u32 j = i; j < i + 0x4000; j += 0x400) { - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - u32 k = common_titlekey_count; - bool titlekey_found = false; - for (; k < _titlekey_count; k++) { - if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { - titlekey_found = true; - break; - } - } - if (titlekey_found) - continue; - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - u8 *titlekey_block = buffer + j + 0x180; - se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); - u8 *salt = M + 1; - u8 *db = M + 0x21; - _mgf1_xor(salt, 0x20, db, 0xdf); - _mgf1_xor(db, 0xdf, salt, 0x20); - if (memcmp(db, null_hash, 0x20)) - continue; - memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); - _titlekey_count++; - } else { - break; - } + u8 *titlekey_block = buffer + j + 0x180; + se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); + u8 *salt = M + 1; + u8 *db = M + 0x21; + _mgf1_xor(salt, 0x20, db, 0xdf); + _mgf1_xor(db, 0xdf, salt, 0x20); + if (memcmp(db, null_hash, 0x20)) + continue; + memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); + _titlekey_count++; + } else { + break; } } - if (br < buf_size) break; } + tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); free(buffer); f_close(&fp); gfx_con_setpos(0, save_y); - TPRINTFARGS("\n%k ", colors[(color_idx++) % 6]); + TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); -dismount: +dismount:; + if (save_ctx) { + save_free_contexts(save_ctx); + free(save_ctx); + } f_mount(NULL, "emmc:", 1); clear_sector_cache = true; nx_emmc_gpt_free(&gpt); diff --git a/source/keys/save.c b/source/keys/save.c new file mode 100644 index 0000000..bcac3b4 --- /dev/null +++ b/source/keys/save.c @@ -0,0 +1,821 @@ +#include +#include "save.h" + +#include "../gfx/gfx.h" +#include "../mem/heap.h" +#include "../sec/se.h" +#include "../utils/types.h" +#include "../utils/util.h" + +#define REMAP_ENTRY_LENGTH 0x20 + +static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) { + *((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7); +} + +static inline void save_bitmap_clear_bit(void *buffer, size_t bit_offset) { + *((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7)); +} + +static inline uint8_t save_bitmap_check_bit(const void *buffer, size_t bit_offset) { + return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7)); +} + +void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size) { + ctx->data_a = layer->data_a; + ctx->data_b = layer->data_b; + ctx->bitmap_storage = (uint8_t *)bitmap; + ctx->block_size = 1 << layer->info.block_size_power; + + ctx->bitmap.data = ctx->bitmap_storage; + ctx->bitmap.bitmap = malloc(bitmap_size >> 3); + + uint32_t bits_remaining = bitmap_size; + uint32_t bitmap_pos = 0; + uint32_t *buffer_pos = (uint32_t *)bitmap; + while (bits_remaining) { + uint32_t bits_to_read = bits_remaining < 32 ? bits_remaining : 32; + uint32_t val = *buffer_pos; + for (uint32_t i = 0; i < bits_to_read; i++) { + if (val & 0x80000000) + save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos); + else + save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos); + bitmap_pos++; + bits_remaining--; + val <<= 1; + } + buffer_pos++; + } +} + +uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; + + uint8_t *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? ctx->data_b : ctx->data_a; + memcpy((uint8_t *)buffer + out_pos, data + in_pos, bytes_to_read); + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) { + remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count); + unsigned int entry_idx = 0; + + for (unsigned int i = 0; i < header->map_segment_count; i++) { + remap_segment_ctx_t *seg = &segments[i]; + seg->entries = malloc(sizeof(remap_entry_ctx_t)); + memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); + seg->offset = map_entries[entry_idx].virtual_offset; + map_entries[entry_idx].segment = seg; + seg->entry_count = 1; + entry_idx++; + + while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { + map_entries[entry_idx].segment = seg; + map_entries[entry_idx - 1].next = &map_entries[entry_idx]; + seg->entries = malloc(sizeof(remap_entry_ctx_t)); + memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); + seg->entry_count++; + entry_idx++; + } + seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset; + } + return segments; +} + +remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) { + uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits)); + if (segment_idx < ctx->header->map_segment_count) { + for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) + if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset) + return &ctx->segments[segment_idx].entries[i]; + } + return NULL; +} + +uint32_t save_remap_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { + remap_entry_ctx_t *entry = save_remap_get_map_entry(ctx, offset); + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint64_t entry_pos = in_pos - entry->virtual_offset; + uint32_t bytes_to_read = entry->virtual_offset_end - in_pos < remaining ? (uint32_t)(entry->virtual_offset_end - in_pos) : remaining; + + switch (ctx->type) { + case STORAGE_BYTES: + f_lseek(ctx->file, ctx->base_storage_offset + entry->physical_offset + entry_pos); + f_read(ctx->file, (uint8_t *)buffer + out_pos, bytes_to_read, NULL); + break; + case STORAGE_DUPLEX: + save_duplex_storage_read(ctx->duplex, (uint8_t *)buffer + out_pos, ctx->base_storage_offset + entry->physical_offset + entry_pos, bytes_to_read); + break; + default: + break; + } + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + + if (in_pos >= entry->virtual_offset_end) + entry = entry->next; + } + return out_pos; +} + +uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_ctx_t *remap, void *buffer, uint64_t offset, size_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos; + uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; + + save_remap_read(remap, (uint8_t *)buffer + out_pos, ctx->journal_data_offset + physical_offset, bytes_to_read); + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, uint64_t master_hash_offset, ivfc_save_hdr_t *ivfc) { + ivfc_level_save_ctx_t *levels = ctx->levels; + levels[0].type = STORAGE_BYTES; + levels[0].hash_offset = master_hash_offset; + for (unsigned int i = 1; i < 4; i++) { + ivfc_level_hdr_t *level = &ivfc->level_headers[i - 1]; + levels[i].type = STORAGE_REMAP; + levels[i].data_offset = level->logical_offset; + levels[i].data_size = level->hash_data_size; + } + if (ivfc->num_levels == 5) { + ivfc_level_hdr_t *data_level = &ivfc->level_headers[ivfc->num_levels - 2]; + levels[ivfc->num_levels - 1].type = STORAGE_JOURNAL; + levels[ivfc->num_levels - 1].data_offset = data_level->logical_offset; + levels[ivfc->num_levels - 1].data_size = data_level->hash_data_size; + } + + struct salt_source_t { + char string[50]; + uint32_t length; + }; + + static struct salt_source_t salt_sources[6] = { + {"HierarchicalIntegrityVerificationStorage::Master", 48}, + {"HierarchicalIntegrityVerificationStorage::L1", 44}, + {"HierarchicalIntegrityVerificationStorage::L2", 44}, + {"HierarchicalIntegrityVerificationStorage::L3", 44}, + {"HierarchicalIntegrityVerificationStorage::L4", 44}, + {"HierarchicalIntegrityVerificationStorage::L5", 44} + }; + integrity_verification_info_ctx_t init_info[ivfc->num_levels]; + + init_info[0].data = &levels[0]; + init_info[0].block_size = 0; + for (unsigned int i = 1; i < ivfc->num_levels; i++) { + init_info[i].data = &levels[i]; + init_info[i].block_size = 1 << ivfc->level_headers[i - 1].block_size; + se_calc_hmac_sha256(init_info[i].salt, ivfc->salt_source, 0x20, salt_sources[i - 1].string, salt_sources[i - 1].length); + } + + ctx->integrity_storages[0].next_level = NULL; + ctx->level_validities = malloc(sizeof(validity_t *) * (ivfc->num_levels - 1)); + for (unsigned int i = 1; i < ivfc->num_levels; i++) { + integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1]; + level_data->hash_storage = &levels[i - 1]; + level_data->base_storage = &levels[i]; + level_data->sector_size = init_info[i].block_size; + level_data->_length = init_info[i].data->data_size; + level_data->sector_count = (level_data->_length + level_data->sector_size - 1) / level_data->sector_size; + memcpy(level_data->salt, init_info[i].salt, 0x20); + level_data->block_validities = calloc(1, sizeof(validity_t) * level_data->sector_count); + ctx->level_validities[i - 1] = level_data->block_validities; + if (i > 1) { + level_data->next_level = &ctx->integrity_storages[i - 2]; + } + } + ctx->data_level = &levels[ivfc->num_levels - 1]; + ctx->_length = ctx->integrity_storages[ivfc->num_levels - 2]._length; +} + +size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { + switch (ctx->type) { + case STORAGE_BYTES: + f_lseek(ctx->save_ctx->file, ctx->hash_offset + offset); + UINT br = 0; + f_read(ctx->save_ctx->file, buffer, count, &br); + return br; + case STORAGE_REMAP: + save_remap_read(&ctx->save_ctx->meta_remap_storage, buffer, ctx->data_offset + offset, count); + return count; + case STORAGE_JOURNAL: + save_journal_storage_read(&ctx->save_ctx->journal_storage, &ctx->save_ctx->data_remap_storage, buffer, ctx->data_offset + offset, count); + return count; + default: + return 0; + } +} + +void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) { + if (count > ctx->sector_size) { + EPRINTF("IVFC read exceeds sector size!\n"); + } + + uint64_t block_index = offset / ctx->sector_size; + + if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { + EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count); + } + + uint8_t hash_buffer[0x20] = {0}; + uint8_t zeroes[0x20] = {0}; + uint64_t hash_pos = block_index * 0x20; + if (ctx->next_level) { + save_ivfc_storage_read(ctx->next_level, hash_buffer, hash_pos, 0x20, verify); + } else { + save_ivfc_level_fread(ctx->hash_storage, hash_buffer, hash_pos, 0x20); + } + + if (!memcmp(hash_buffer, zeroes, 0x20)) { + memset(buffer, 0, count); + ctx->block_validities[block_index] = VALIDITY_VALID; + return; + } + + save_ivfc_level_fread(ctx->base_storage, buffer, offset, count); + + if (!(verify && ctx->block_validities[block_index] == VALIDITY_UNCHECKED)) { + return; + } + + uint8_t hash[0x20] = {0}; + uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20); + memcpy(data_buffer, ctx->salt, 0x20); + memcpy(data_buffer + 0x20, buffer, count); + + se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20); + hash[0x1F] |= 0x80; + + free(data_buffer); + if (memcmp(hash_buffer, hash, 0x20)) { + ctx->block_validities[block_index] = VALIDITY_INVALID; + } else { + ctx->block_validities[block_index] = VALIDITY_VALID; + } + + if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { + EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count); + } +} + +uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) { + uint32_t length = 1; + uint32_t entry_index = allocation_table_block_to_entry_index(entry->next); + + allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE); + if ((entries[0].next & 0x80000000) == 0) { + if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) { + EPRINTF("Invalid range entry in allocation table!\n"); + } + } else { + length = entries[1].next - entry_index + 1; + } + + if (allocation_table_is_list_end(&entries[0])) { + entry->next = 0xFFFFFFFF; + } else { + entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0])); + } + + if (allocation_table_is_list_start(&entries[0])) { + entry->prev = 0xFFFFFFFF; + } else { + entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0])); + } + + return length; +} + +uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) { + allocation_table_entry_t entry; + entry.next = block_index; + uint32_t total_length = 0; + uint32_t table_size = ctx->header->allocation_table_block_count; + uint32_t nodes_iterated = 0; + + while (entry.next != 0xFFFFFFFF) { + total_length += save_allocation_table_read_entry_with_length(ctx, &entry); + nodes_iterated++; + if (nodes_iterated > table_size) { + EPRINTF("Cycle detected in allocation table!\n"); + return 0; + } + } + return total_length; +} + +uint64_t save_allocation_table_get_free_space_size(save_filesystem_ctx_t *ctx) { + uint32_t free_list_start = save_allocation_table_get_free_list_block_index(&ctx->allocation_table); + + if (free_list_start == 0xFFFFFFFF) return 0; + + return ctx->header->block_size * save_allocation_table_get_list_length(&ctx->allocation_table, free_list_start); +} + +void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) { + ctx->fat = table; + ctx->physical_block = initial_block; + ctx->virtual_block = 0; + + allocation_table_entry_t entry; + entry.next = initial_block; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + if (ctx->prev_block != 0xFFFFFFFF) { + EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block); + } +} + +int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) { + if (ctx->next_block == 0xFFFFFFFF) return 0; + + ctx->virtual_block += ctx->current_segment_size; + ctx->physical_block = ctx->next_block; + + allocation_table_entry_t entry; + entry.next = ctx->next_block; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + return 1; +} + +int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) { + if (ctx->prev_block == 0xFFFFFFFF) return 0; + + ctx->physical_block = ctx->prev_block; + + allocation_table_entry_t entry; + entry.next = ctx->prev_block; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + ctx->virtual_block -= ctx->current_segment_size; + + return 1; +} + +int save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) { + while (1) { + if (block < ctx->virtual_block) { + if (!save_allocation_table_iterator_move_prev(ctx)) return 0; + } else if (block >= ctx->virtual_block + ctx->current_segment_size) { + if (!save_allocation_table_iterator_move_next(ctx)) return 0; + } else { + return 1; + } + + } +} + +uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { + allocation_table_iterator_ctx_t iterator; + save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block); + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + save_allocation_table_iterator_seek(&iterator, block_num); + + uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size); + uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos; + + uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos; + uint32_t bytes_to_read = remaining < remaining_in_segment ? remaining : remaining_in_segment; + + uint32_t sector_size = ctx->base_storage->integrity_storages[3].sector_size; + uint32_t chunk_remaining = bytes_to_read; + for (unsigned int i = 0; i < bytes_to_read; i += sector_size) { + uint32_t bytes_to_request = chunk_remaining < sector_size ? chunk_remaining : sector_size; + save_ivfc_storage_read(&ctx->base_storage->integrity_storages[3], (uint8_t *)buffer + out_pos + i, physical_offset + i, bytes_to_request, ctx->base_storage->data_level->save_ctx->tool_ctx.action & ACTION_VERIFY); + chunk_remaining -= bytes_to_request; + } + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) { + if (!ctx->capacity) + save_allocation_table_storage_read(&ctx->storage, &ctx->capacity, 4, 4); + return ctx->capacity; +} + +uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *entry) { + return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); +} + +int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value) { + if (index >= save_fs_list_get_capacity(ctx)) { + return 0; + } + save_fs_list_read_entry(ctx, index, value); + return 1; +} + +uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) { + save_fs_list_entry_t entry; + uint32_t capacity = save_fs_list_get_capacity(ctx); + save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry); + uint32_t prev; + if (!prev_index) { + prev_index = &prev; + } + *prev_index = ctx->used_list_head_index; + uint32_t index = entry.next; + while (index) { + if (index > capacity) { + EPRINTFARGS("Save entry index %d out of range!", index); + } + save_fs_list_read_entry(ctx, index, &entry); + if (entry.parent == key->parent && !strcmp(entry.name, key->name)) { + return index; + } + *prev_index = index; + index = entry.next; + } + *prev_index = 0xFFFFFFFF; + return 0xFFFFFFFF; +} + +int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) { + key->parent = 0; + char *pos = strchr(path, '/'); + while (pos) { + memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); + char *tmp = strchr(pos, '/'); + if (!tmp) { + memcpy(key->name, pos, strlen(pos)); + break; + } + memcpy(key->name, pos, tmp - pos); + key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL); + if (key->parent == 0xFFFFFFFF) + return 0; + pos = tmp + 1; + } + return 1; +} + +int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) { + if (position->next_file == 0) { + return 0; + } + save_fs_list_entry_t entry; + if(!save_fs_list_get_value(&ctx->file_table, position->next_file, &entry)) { + return 0; + } + position->next_file = entry.value.next_sibling; + memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); + memcpy(info, &entry.value.save_file_info, sizeof(save_file_info_t)); + return 1; +} + +int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) { + if (position->next_directory == 0) { + return 0; + } + save_fs_list_entry_t entry; + if(!save_fs_list_get_value(&ctx->directory_table, position->next_directory, &entry)) { + return 0; + } + position->next_directory = entry.value.next_sibling; + memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); + return 1; +} + +int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry) { + save_entry_key_t key; + if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) { + EPRINTF("Unable to locate file."); + return 0; + } + u32 index = save_fs_get_index_from_key(&ctx->file_table, &key, NULL); + if (index == 0xFFFFFFFF) { + EPRINTF("Unable to get table index for file."); + return 0; + } + if (!save_fs_list_get_value(&ctx->file_table, index, entry)) { + EPRINTF("Unable to get file entry from index."); + return 0; + } + return 1; +} + +void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { + storage_ctx->base_storage = ctx->base_storage; + storage_ctx->fat = &ctx->allocation_table; + storage_ctx->block_size = (uint32_t)ctx->header->block_size; + storage_ctx->initial_block = block_index; + storage_ctx->_length = block_index == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(storage_ctx->fat, block_index) * storage_ctx->block_size; +} + +void save_filesystem_init(save_filesystem_ctx_t *ctx, void *fat, save_fs_header_t *save_fs_header, fat_header_t *fat_header) { + ctx->allocation_table.base_storage = fat; + ctx->allocation_table.header = fat_header; + ctx->allocation_table.free_list_entry_index = 0; + ctx->header = save_fs_header; + + save_open_fat_storage(ctx, &ctx->file_table.directory_table.storage, fat_header->directory_table_block); + save_open_fat_storage(ctx, &ctx->file_table.file_table.storage, fat_header->file_table_block); + ctx->file_table.file_table.free_list_head_index = 0; + ctx->file_table.file_table.used_list_head_index = 1; + ctx->file_table.directory_table.free_list_head_index = 0; + ctx->file_table.directory_table.used_list_head_index = 1; +} + +validity_t save_ivfc_validate(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { + validity_t result = VALIDITY_VALID; + for (unsigned int i = 0; i < ivfc->num_levels - 1 && result != VALIDITY_INVALID; i++) { + integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[i]; + + uint64_t block_size = storage->sector_size; + uint32_t block_count = (uint32_t)((storage->_length + block_size - 1) / block_size); + + uint8_t *buffer = malloc(block_size); + + for (unsigned int j = 0; j < block_count; j++) { + if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_UNCHECKED) { + uint32_t to_read = storage->_length - block_size * j < block_size ? storage->_length - block_size * j : block_size; + save_ivfc_storage_read(storage, buffer, block_size * j, to_read, 1); + } + if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_INVALID) { + result = VALIDITY_INVALID; + break; + } + } + free(buffer); + } + + return result; +} + +void save_ivfc_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { + for (unsigned int i = 0; i < ivfc->num_levels - 1; i++) { + validity_t level_validity = VALIDITY_VALID; + for (unsigned int j = 0; j < ctx->integrity_storages[i].sector_count; j++) { + if (ctx->level_validities[i][j] == VALIDITY_INVALID) { + level_validity = VALIDITY_INVALID; + break; + } + if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) { + level_validity = VALIDITY_UNCHECKED; + } + } + ctx->levels[i].hash_validity = level_validity; + } +} + +validity_t save_filesystem_verify(save_ctx_t *ctx) { + validity_t journal_validity = save_ivfc_validate(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); + save_ivfc_set_level_validities(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); + + if (!ctx->fat_ivfc_storage.levels[0].save_ctx) return journal_validity; + + validity_t fat_validity = save_ivfc_validate(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); + save_ivfc_set_level_validities(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); + + if (journal_validity != VALIDITY_VALID) return journal_validity; + if (fat_validity != VALIDITY_VALID) return fat_validity; + + return journal_validity; +} + +void save_process(save_ctx_t *ctx) { + /* Try to parse Header A. */ + f_lseek(ctx->file, 0); + if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { + EPRINTF("Failed to read save header!\n"); + } + + save_process_header(ctx); + + if (ctx->header_hash_validity == VALIDITY_INVALID) { + /* Try to parse Header B. */ + f_lseek(ctx->file, 0x4000); + if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { + EPRINTF("Failed to read save header!\n"); + } + + save_process_header(ctx); + + if (ctx->header_hash_validity == VALIDITY_INVALID) { + EPRINTF("Error: Save header is invalid!\n"); + } + } + + unsigned char cmac[0x10]; + memset(cmac, 0, 0x10); + se_aes_key_set(3, ctx->save_mac_key, 0x10); + se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); + if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { + ctx->header_cmac_validity = VALIDITY_VALID; + } else { + ctx->header_cmac_validity = VALIDITY_INVALID; + } + + /* Initialize remap storages. */ + ctx->data_remap_storage.type = STORAGE_BYTES; + ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset; + ctx->data_remap_storage.header = &ctx->header.main_remap_header; + ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); + ctx->data_remap_storage.file = ctx->file; + f_lseek(ctx->file, ctx->header.layout.file_map_entry_offset); + for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) { + f_read(ctx->file, &ctx->data_remap_storage.map_entries[i], 0x20, NULL); + ctx->data_remap_storage.map_entries[i].physical_offset_end = ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size; + ctx->data_remap_storage.map_entries[i].virtual_offset_end = ctx->data_remap_storage.map_entries[i].virtual_offset + ctx->data_remap_storage.map_entries[i].size; + } + + /* Initialize data remap storage. */ + ctx->data_remap_storage.segments = save_remap_init_segments(ctx->data_remap_storage.header, ctx->data_remap_storage.map_entries, ctx->data_remap_storage.header->map_entry_count); + + /* Initialize duplex storage. */ + ctx->duplex_layers[0].data_a = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_a; + ctx->duplex_layers[0].data_b = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_b; + memcpy(&ctx->duplex_layers[0].info, &ctx->header.duplex_header.layers[0], sizeof(duplex_info_t)); + + ctx->duplex_layers[1].data_a = malloc(ctx->header.layout.duplex_l1_size); + save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size); + ctx->duplex_layers[1].data_b = malloc(ctx->header.layout.duplex_l1_size); + save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size); + memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t)); + + ctx->duplex_layers[2].data_a = malloc(ctx->header.layout.duplex_data_size); + save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size); + ctx->duplex_layers[2].data_b = malloc(ctx->header.layout.duplex_data_size); + save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size); + memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t)); + + /* Initialize hierarchical duplex storage. */ + uint8_t *bitmap = ctx->header.layout.duplex_index == 1 ? ctx->duplex_layers[0].data_b : ctx->duplex_layers[0].data_a; + save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size); + ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size; + + bitmap = malloc(ctx->duplex_storage.layers[0]._length); + save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length); + save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length); + ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size; + + ctx->duplex_storage.data_layer = ctx->duplex_storage.layers[1]; + + /* Initialize meta remap storage. */ + ctx->meta_remap_storage.type = STORAGE_DUPLEX; + ctx->meta_remap_storage.duplex = &ctx->duplex_storage.data_layer; + ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; + ctx->meta_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); + ctx->meta_remap_storage.file = ctx->file; + f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset); + for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) { + f_read(ctx->file, &ctx->meta_remap_storage.map_entries[i], 0x20, NULL); + ctx->meta_remap_storage.map_entries[i].physical_offset_end = ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size; + ctx->meta_remap_storage.map_entries[i].virtual_offset_end = ctx->meta_remap_storage.map_entries[i].virtual_offset + ctx->meta_remap_storage.map_entries[i].size; + } + + ctx->meta_remap_storage.segments = save_remap_init_segments(ctx->meta_remap_storage.header, ctx->meta_remap_storage.map_entries, ctx->meta_remap_storage.header->map_entry_count); + + /* Initialize journal map. */ + ctx->journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size); + save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size); + + /* Initialize journal storage. */ + ctx->journal_storage.header = &ctx->header.journal_header; + ctx->journal_storage.journal_data_offset = ctx->header.layout.journal_data_offset; + ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; + ctx->journal_storage.file = ctx->file; + ctx->journal_storage.map.header = &ctx->header.map_header; + ctx->journal_storage.map.map_storage = ctx->journal_map_info.map_storage; + ctx->journal_storage.map.entries = malloc(sizeof(journal_map_entry_t) * ctx->journal_storage.map.header->main_data_block_count); + uint32_t *pos = (uint32_t *)ctx->journal_storage.map.map_storage; + for (unsigned int i = 0; i < ctx->journal_storage.map.header->main_data_block_count; i++) { + ctx->journal_storage.map.entries[i].virtual_index = i; + ctx->journal_storage.map.entries[i].physical_index = *pos & 0x7FFFFFFF; + pos += 2; + } + ctx->journal_storage.block_size = ctx->journal_storage.header->block_size; + ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; + + /* Initialize core IVFC storage. */ + for (unsigned int i = 0; i < 5; i++) { + ctx->core_data_ivfc_storage.levels[i].save_ctx = ctx; + } + save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header); + + /* Initialize FAT storage. */ + if (ctx->header.layout.version < 0x50000) { + ctx->fat_storage = malloc(ctx->header.layout.fat_size); + save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size); + } else { + for (unsigned int i = 0; i < 5; i++) { + ctx->fat_ivfc_storage.levels[i].save_ctx = ctx; + } + save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header); + ctx->fat_storage = malloc(ctx->fat_ivfc_storage._length); + save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length); + } + + if (ctx->tool_ctx.action & ACTION_VERIFY) { + save_filesystem_verify(ctx); + } + + /* Initialize core save filesystem. */ + ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage; + save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header); +} + +void save_process_header(save_ctx_t *ctx) { + if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS || + ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL || + ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || + ctx->header.meta_remap_header.magic != MAGIC_RMAP) { + EPRINTF("Error: Save header is corrupt!\n"); + } + + ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; + ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; + + uint8_t hash[0x20]; + se_calc_sha256(hash, &ctx->header.duplex_header, 0x3D00); + ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; + + ctx->header.data_ivfc_header.num_levels = 5; + + if (ctx->header.layout.version >= 0x50000) { + ctx->header.fat_ivfc_header.num_levels = 4; + } +} + +void save_free_contexts(save_ctx_t *ctx) { + for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { + for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) { + free(&ctx->data_remap_storage.segments[i].entries[j]); + } + } + free(ctx->data_remap_storage.segments); + for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { + for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) { + free(&ctx->meta_remap_storage.segments[i].entries[j]); + } + } + free(ctx->meta_remap_storage.segments); + free(ctx->data_remap_storage.map_entries); + free(ctx->meta_remap_storage.map_entries); + free(ctx->duplex_storage.layers[0].bitmap.bitmap); + free(ctx->duplex_storage.layers[1].bitmap.bitmap); + free(ctx->duplex_storage.layers[1].bitmap_storage); + for (unsigned int i = 1; i < 3; i++) { + free(ctx->duplex_layers[i].data_a); + free(ctx->duplex_layers[i].data_b); + } + free(ctx->journal_map_info.map_storage); + free(ctx->journal_storage.map.entries); + for (unsigned int i = 0; i < ctx->header.data_ivfc_header.num_levels - 1; i++) { + free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); + } + free(ctx->core_data_ivfc_storage.level_validities); + if (ctx->header.layout.version >= 0x50000) { + for (unsigned int i = 0; i < ctx->header.fat_ivfc_header.num_levels - 1; i++) { + free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); + } + } + free(ctx->fat_ivfc_storage.level_validities); + free(ctx->fat_storage); +} diff --git a/source/keys/save.h b/source/keys/save.h new file mode 100644 index 0000000..ea44906 --- /dev/null +++ b/source/keys/save.h @@ -0,0 +1,489 @@ +#ifndef _SAVE_H +#define _SAVE_H + +#include +#include + +#include "../libs/fatfs/ff.h" + +#define SAVE_HEADER_SIZE 0x4000 +#define SAVE_FAT_ENTRY_SIZE 8 +#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40 +#define SAVE_FS_LIST_ENTRY_SIZE 0x60 + +#define IVFC_MAX_LEVEL 6 + +#define MAGIC_DISF 0x46534944 +#define MAGIC_DPFS 0x53465044 +#define MAGIC_JNGL 0x4C474E4A +#define MAGIC_SAVE 0x45564153 +#define MAGIC_RMAP 0x50414D52 +#define MAGIC_IVFC 0x43465649 + +typedef enum { + VALIDITY_UNCHECKED = 0, + VALIDITY_INVALID, + VALIDITY_VALID +} validity_t; + +typedef struct save_ctx_t save_ctx_t; + +typedef struct { + uint32_t magic; /* DISF */ + uint32_t version; + uint8_t hash[0x20]; + uint64_t file_map_entry_offset; + uint64_t file_map_entry_size; + uint64_t meta_map_entry_offset; + uint64_t meta_map_entry_size; + uint64_t file_map_data_offset; + uint64_t file_map_data_size; + uint64_t duplex_l1_offset_a; + uint64_t duplex_l1_offset_b; + uint64_t duplex_l1_size; + uint64_t duplex_data_offset_a; + uint64_t duplex_data_offset_b; + uint64_t duplex_data_size; + uint64_t journal_data_offset; + uint64_t journal_data_size_a; + uint64_t journal_data_size_b; + uint64_t journal_size; + uint64_t duplex_master_offset_a; + uint64_t duplex_master_offset_b; + uint64_t duplex_master_size; + uint64_t ivfc_master_hash_offset_a; + uint64_t ivfc_master_hash_offset_b; + uint64_t ivfc_master_hash_size; + uint64_t journal_map_table_offset; + uint64_t journal_map_table_size; + uint64_t journal_physical_bitmap_offset; + uint64_t journal_physical_bitmap_size; + uint64_t journal_virtual_bitmap_offset; + uint64_t journal_virtual_bitmap_size; + uint64_t journal_free_bitmap_offset; + uint64_t journal_free_bitmap_size; + uint64_t ivfc_l1_offset; + uint64_t ivfc_l1_size; + uint64_t ivfc_l2_offset; + uint64_t ivfc_l2_size; + uint64_t ivfc_l3_offset; + uint64_t ivfc_l3_size; + uint64_t fat_offset; + uint64_t fat_size; + uint64_t duplex_index; + uint64_t fat_ivfc_master_hash_a; + uint64_t fat_ivfc_master_hash_b; + uint64_t fat_ivfc_l1_offset; + uint64_t fat_ivfc_l1_size; + uint64_t fat_ivfc_l2_offset; + uint64_t fat_ivfc_l2_size; + uint8_t _0x190[0x70]; +} fs_layout_t; + +#pragma pack(push, 1) +typedef struct { + uint64_t offset; + uint64_t length; + uint32_t block_size_power; +} duplex_info_t; +#pragma pack(pop) + +typedef struct { + uint32_t magic; /* DPFS */ + uint32_t version; + duplex_info_t layers[3]; +} duplex_header_t; + +typedef struct { + uint32_t version; + uint32_t main_data_block_count; + uint32_t journal_block_count; + uint32_t _0x0C; +} journal_map_header_t; + +typedef struct { + uint32_t magic; /* JNGL */ + uint32_t version; + uint64_t total_size; + uint64_t journal_size; + uint64_t block_size; +} journal_header_t; + +typedef struct { + uint32_t magic; /* SAVE */ + uint32_t version; + uint64_t block_count; + uint64_t block_size; +} save_fs_header_t; + +typedef struct { + uint64_t block_size; + uint64_t allocation_table_offset; + uint32_t allocation_table_block_count; + uint32_t _0x14; + uint64_t data_offset; + uint32_t data_block_count; + uint32_t _0x24; + uint32_t directory_table_block; + uint32_t file_table_block; +} fat_header_t; + +typedef struct { + uint32_t magic; /* RMAP */ + uint32_t version; + uint32_t map_entry_count; + uint32_t map_segment_count; + uint32_t segment_bits; + uint8_t _0x14[0x2C]; +} remap_header_t; + +typedef struct remap_segment_ctx_t remap_segment_ctx_t; +typedef struct remap_entry_ctx_t remap_entry_ctx_t; + +#pragma pack(push, 1) +struct remap_entry_ctx_t { + uint64_t virtual_offset; + uint64_t physical_offset; + uint64_t size; + uint32_t alignment; + uint32_t _0x1C; + uint64_t virtual_offset_end; + uint64_t physical_offset_end; + remap_segment_ctx_t *segment; + remap_entry_ctx_t *next; +}; +#pragma pack(pop) + +struct remap_segment_ctx_t{ + uint64_t offset; + uint64_t length; + remap_entry_ctx_t *entries; + uint64_t entry_count; +}; + +typedef struct { + uint8_t *data; + uint8_t *bitmap; +} duplex_bitmap_t; + +typedef struct { + uint32_t block_size; + uint8_t *bitmap_storage; + uint8_t *data_a; + uint8_t *data_b; + duplex_bitmap_t bitmap; + uint64_t _length; +} duplex_storage_ctx_t; + +enum base_storage_type { + STORAGE_BYTES = 0, + STORAGE_DUPLEX = 1, + STORAGE_REMAP = 2, + STORAGE_JOURNAL = 3 +}; + +typedef struct { + remap_header_t *header; + remap_entry_ctx_t *map_entries; + remap_segment_ctx_t *segments; + enum base_storage_type type; + uint64_t base_storage_offset; + duplex_storage_ctx_t *duplex; + FIL *file; +} remap_storage_ctx_t; + +typedef struct { + uint64_t title_id; + uint8_t user_id[0x10]; + uint64_t save_id; + uint8_t save_data_type; + uint8_t _0x21[0x1F]; + uint64_t save_owner_id; + uint64_t timestamp; + uint64_t _0x50; + uint64_t data_size; + uint64_t journal_size; + uint64_t commit_id; +} extra_data_t; + +typedef struct { + uint64_t logical_offset; + uint64_t hash_data_size; + uint32_t block_size; + uint32_t reserved; +} ivfc_level_hdr_t; + +typedef struct { + uint32_t magic; + uint32_t id; + uint32_t master_hash_size; + uint32_t num_levels; + ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL]; + uint8_t salt_source[0x20]; +} ivfc_save_hdr_t; + +#pragma pack(push, 1) +typedef struct { + uint8_t cmac[0x10]; + uint8_t _0x10[0xF0]; + fs_layout_t layout; + duplex_header_t duplex_header; + ivfc_save_hdr_t data_ivfc_header; + uint32_t _0x404; + journal_header_t journal_header; + journal_map_header_t map_header; + uint8_t _0x438[0x1D0]; + save_fs_header_t save_header; + fat_header_t fat_header; + remap_header_t main_remap_header, meta_remap_header; + uint64_t _0x6D0; + extra_data_t extra_data; + uint8_t _0x748[0x390]; + ivfc_save_hdr_t fat_ivfc_header; + uint8_t _0xB98[0x3468]; +} save_header_t; +#pragma pack(pop) + +typedef struct { + duplex_storage_ctx_t layers[2]; + duplex_storage_ctx_t data_layer; + uint64_t _length; +} hierarchical_duplex_storage_ctx_t; + +typedef struct { + uint8_t *data_a; + uint8_t *data_b; + duplex_info_t info; +} duplex_fs_layer_info_t; + +typedef struct { + uint8_t *map_storage; + uint8_t *physical_block_bitmap; + uint8_t *virtual_block_bitmap; + uint8_t *free_block_bitmap; +} journal_map_params_t; + +typedef struct { + uint32_t physical_index; + uint32_t virtual_index; +} journal_map_entry_t; + + +typedef struct { + journal_map_header_t *header; + journal_map_entry_t *entries; + uint8_t *map_storage; +} journal_map_ctx_t; + +typedef struct { + journal_map_ctx_t map; + journal_header_t *header; + uint32_t block_size; + uint64_t journal_data_offset; + uint64_t _length; + FIL *file; +} journal_storage_ctx_t; + +typedef struct { + uint64_t data_offset; + uint64_t data_size; + uint64_t hash_offset; + uint32_t hash_block_size; + validity_t hash_validity; + enum base_storage_type type; + save_ctx_t *save_ctx; +} ivfc_level_save_ctx_t; + +typedef struct { + ivfc_level_save_ctx_t *data; + uint32_t block_size; + uint8_t salt[0x20]; +} integrity_verification_info_ctx_t; + + +typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t; + +struct integrity_verification_storage_ctx_t { + ivfc_level_save_ctx_t *hash_storage; + ivfc_level_save_ctx_t *base_storage; + validity_t *block_validities; + uint8_t salt[0x20]; + uint32_t sector_size; + uint32_t sector_count; + uint64_t _length; + integrity_verification_storage_ctx_t *next_level; +}; + +typedef struct { + ivfc_level_save_ctx_t levels[5]; + ivfc_level_save_ctx_t *data_level; + validity_t **level_validities; + uint64_t _length; + integrity_verification_storage_ctx_t integrity_storages[4]; +} hierarchical_integrity_verification_storage_ctx_t; + +typedef struct { + uint32_t prev; + uint32_t next; +} allocation_table_entry_t; + +typedef struct { + uint32_t free_list_entry_index; + void *base_storage; + fat_header_t *header; +} allocation_table_ctx_t; + +typedef struct { + hierarchical_integrity_verification_storage_ctx_t *base_storage; + uint32_t block_size; + uint32_t initial_block; + allocation_table_ctx_t *fat; + uint64_t _length; +} allocation_table_storage_ctx_t; + +typedef struct { + allocation_table_ctx_t *fat; + uint32_t virtual_block; + uint32_t physical_block; + uint32_t current_segment_size; + uint32_t next_block; + uint32_t prev_block; +} allocation_table_iterator_ctx_t; + +typedef struct { + char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; + uint32_t parent; +} save_entry_key_t; + +#pragma pack(push, 1) +typedef struct { + uint32_t start_block; + uint64_t length; + uint32_t _0xC[2]; +} save_file_info_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct { + uint32_t next_directory; + uint32_t next_file; + uint32_t _0x8[3]; +} save_find_position_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct { + uint32_t next_sibling; + union { /* Save table entry type. Size = 0x14. */ + save_file_info_t save_file_info; + save_find_position_t save_find_position; + }; +} save_table_entry_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct { + uint32_t parent; + char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; + save_table_entry_t value; + uint32_t next; +} save_fs_list_entry_t; +#pragma pack(pop) + +typedef struct { + uint32_t free_list_head_index; + uint32_t used_list_head_index; + allocation_table_storage_ctx_t storage; + uint32_t capacity; +} save_filesystem_list_ctx_t; + +typedef struct { + save_filesystem_list_ctx_t file_table; + save_filesystem_list_ctx_t directory_table; +} hierarchical_save_file_table_ctx_t; + +typedef struct { + hierarchical_integrity_verification_storage_ctx_t *base_storage; + allocation_table_ctx_t allocation_table; + save_fs_header_t *header; + hierarchical_save_file_table_ctx_t file_table; +} save_filesystem_ctx_t; + +#define ACTION_VERIFY (1<<2) + +struct save_ctx_t { + save_header_t header; + FIL *file; + struct { + FIL *file; + uint32_t action; + } tool_ctx; + validity_t header_cmac_validity; + validity_t header_hash_validity; + uint8_t *data_ivfc_master; + uint8_t *fat_ivfc_master; + remap_storage_ctx_t data_remap_storage; + remap_storage_ctx_t meta_remap_storage; + duplex_fs_layer_info_t duplex_layers[3]; + hierarchical_duplex_storage_ctx_t duplex_storage; + journal_storage_ctx_t journal_storage; + journal_map_params_t journal_map_info; + hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage; + hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage; + uint8_t *fat_storage; + save_filesystem_ctx_t save_filesystem_core; + uint8_t save_mac_key[0x10]; +}; + +static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) { + return entry_index - 1; +} + +static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) { + return block_index + 1; +} + +static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) { + return (entry->next & 0x7FFFFFFF) == 0; +} + +static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) { + return entry->prev == 0x80000000; +} + + +static inline int allocation_table_get_next(allocation_table_entry_t *entry) { + return entry->next & 0x7FFFFFFF; +} + +static inline int allocation_table_get_prev(allocation_table_entry_t *entry) { + return entry->prev & 0x7FFFFFFF; +} + +static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { + return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE); +} + +static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) { + return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index)); +} + +static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) { + return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); +} + +void save_process(save_ctx_t *ctx); +void save_process_header(save_ctx_t *ctx); +void save_save(save_ctx_t *ctx); +void save_print(save_ctx_t *ctx); + +void save_free_contexts(save_ctx_t *ctx); + +void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index); +uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count); +int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value); +uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index); +int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path); +int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry); + +#endif From 6ad7192199cdf7114cebc99455f575d031d51fd5 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 28 Oct 2019 09:54:01 -0600 Subject: [PATCH 036/166] Move key offsets to struct for cleaner code --- source/hos/pkg1.c | 31 +++++---- source/hos/pkg1.h | 13 ++++ source/keys/keys.c | 165 ++++++--------------------------------------- 3 files changed, 52 insertions(+), 157 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index d00937f..878cfb9 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -22,20 +22,25 @@ #include "pkg1.h" #include "../sec/se.h" +#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_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} + static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0 }, //1.0.0 - { "20170210155124", 0 }, //2.0.0 - 2.3.0 - { "20170519101410", 1 }, //3.0.0 - { "20170710161758", 2 }, //3.0.1 - 3.0.2 - { "20170921172629", 3 }, //4.0.0 - 4.1.0 - { "20180220163747", 4 }, //5.0.0 - 5.1.0 - { "20180802162753", 5 }, //6.0.0 - 6.1.0 - { "20181107105733", 6 }, //6.2.0 - { "20181218175730", 7 }, //7.0.0 - { "20190208150037", 7 }, //7.0.1 - { "20190314172056", 7 }, //8.0.0 - 8.0.1 - { "20190531152432", 8 }, //8.1.0 - { "20190809135709", 9 }, //9.0.0 - 9.0.1 + { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0 + { "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0 + { "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0 + { "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2 + { "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.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 + { "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 + { "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1 + { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 + { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0 + { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 { NULL } //End. }; diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index c0be0ac..1d1e4ad 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -19,10 +19,23 @@ #include "../utils/types.h" +typedef struct _key_info_t +{ + u32 start_offset; + u32 hks_offset; + bool hks_offset_is_from_end; + u32 alignment; + u32 hash_max; + u8 hash_order[13]; + u32 es_offset; + u32 ssl_offset; +} key_info_t; + typedef struct _pkg1_id_t { const char *id; u32 kb; + key_info_t key_info; } pkg1_id_t; const pkg1_id_t *pkg1_identify(u8 *pkg1); diff --git a/source/keys/keys.c b/source/keys/keys.c index ae7dfe1..b9f9fe2 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -453,96 +453,33 @@ get_tsec: ; pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]); - u8 hash_index = 0, hash_max = 11, hash_order[13], - key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; - u32 start_offset = 0, hks_offset_from_end = ki->kip1->sections[2].size_decomp, alignment = 0x10; + u8 hash_index = 0; + const u8 key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; - // the FS keys appear in different orders if (!memcmp(pkg1_id->id, "2016", 4)) { - // 1.0.0 doesn't have SD keys at all - hash_max = 6; - // the first key isn't aligned with the rest + // 1.0.0 doesn't have SD keys at all and the first key isn't aligned with the rest memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); hash_index = 1; - start_offset = 0x1b517; - hks_offset_from_end = 0x125bc2; - u8 temp[7] = {2, 3, 4, 0, 5, 6, 1}; - memcpy(hash_order, temp, 7); - } else { - // 2.0.0 - 8.0.0 - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x1d226; - hks_offset_from_end -= 0x26fe; - break; - case KB_FIRMWARE_VERSION_300: - start_offset = 0x1ffa6; - hks_offset_from_end -= 0x298b; - break; - case KB_FIRMWARE_VERSION_301: - start_offset = 0x20026; - hks_offset_from_end -= 0x29ab; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x1c64c; - hks_offset_from_end -= 0x37eb; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x1f3b4; - hks_offset_from_end -= 0x465b; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x27350; - hks_offset_from_end = 0x17ff5; - alignment = 8; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x29c50; - hks_offset_from_end -= 0x6a73; - alignment = 8; - break; - case KB_FIRMWARE_VERSION_900: - start_offset = 0x2ec10; - hks_offset_from_end -= 0x5573; - alignment = 1; // RIP - break; - } - - if (pkg1_id->kb <= KB_FIRMWARE_VERSION_500) { - u8 temp[12] = {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}; - memcpy(hash_order, temp, 12); - } else if (pkg1_id->kb <= KB_FIRMWARE_VERSION_620) { - u8 temp[12] = {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}; - memcpy(hash_order, temp, 12); - } else { - u8 temp[13] = {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}; - memcpy(hash_order, temp, 13); - hash_max = 12; - } } u8 temp_hash[0x20]; - for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) { + for (u32 i = ki->kip1->sections[0].size_comp + pkg1_id->key_info.start_offset; i < ki->size - 0x20; ) { minerva_periodic_training(); - se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]); - if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) { - memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]); - /*if (hash_index == hash_max) { - TPRINTFARGS("%d: %x end -%x", hash_index, (*(ki->kip1->data + i)), ki->size - i); - } else { - TPRINTFARGS("%d: %x rodata +%x", hash_index, (*(ki->kip1->data + i)), i - ki->kip1->sections[0].size_comp); - }*/ - i += key_lengths[hash_order[hash_index]]; - if (hash_index == hash_max - 1) { - i = ki->size - hks_offset_from_end; - } else if (hash_index == hash_max) { + se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); + if (!memcmp(temp_hash, fs_hashes_sha256[pkg1_id->key_info.hash_order[hash_index]], 0x20)) { + memcpy(fs_keys[pkg1_id->key_info.hash_order[hash_index]], ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); + i += key_lengths[pkg1_id->key_info.hash_order[hash_index]]; + if (hash_index == pkg1_id->key_info.hash_max - 1) { + if (pkg1_id->key_info.hks_offset_is_from_end) + i = ki->size - pkg1_id->key_info.hks_offset; + else + i = ki->size - (ki->kip1->sections[2].size_decomp - pkg1_id->key_info.hks_offset); + } else if (hash_index == pkg1_id->key_info.hash_max) { break; } hash_index++; } else { - i += alignment; + i += pkg1_id->key_info.alignment; } } pkg2_done: @@ -632,7 +569,6 @@ pkg2_done: } path[25] = '/'; - start_offset = 0; while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); memcpy(path + 26, fno.fname, 36); @@ -647,44 +583,14 @@ pkg2_done: se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); // es doesn't contain es key sources on 1.0.0 if (memcmp(pkg1_id->id, "2016", 4) && *(u32*)(dec_header + 0x210) == 0x33 && dec_header[0x205] == 0) { - // es (offset 0x210 is lower half of titleid, 0x205 == 0 means it's program nca, not meta) - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x557b; - break; - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - start_offset = 0x552d; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x5382; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x5a63; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x5674; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x5563; - break; - case KB_FIRMWARE_VERSION_900: - start_offset = 0x6495; - break; - } - hash_order[2] = 2; - if (pkg1_id->kb < KB_FIRMWARE_VERSION_500) { - hash_order[0] = 0; - hash_order[1] = 1; - } else { + u8 hash_order[3] = {0, 1, 2}; + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { hash_order[0] = 1; hash_order[1] = 0; } hash_index = 0; // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0, key_area_key); + temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); for (u32 i = 0; i <= 0xb0; ) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { @@ -701,36 +607,7 @@ pkg2_done: temp_file = NULL; titles_found++; } else if (*(u32*)(dec_header + 0x210) == 0x24 && dec_header[0x205] == 0) { - // ssl - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x3d41a; - break; - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - start_offset = 0x3cb81; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x3711c; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x37901; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x1d5be; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x1d437; - break; - case KB_FIRMWARE_VERSION_900: - start_offset = 0x1d807; - break; - } - if (!memcmp(pkg1_id->id, "2016", 4)) - start_offset = 0x449dc; - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70, key_area_key); + temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { @@ -1150,8 +1027,8 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char temp_name[0x40] = {0}; - for (u32 i = start_key; i < num_keys + start_key; i++) { - sprintf(temp_name, "%s_%02x", name, i); + for (u32 i = 0; i < num_keys; i++) { + sprintf(temp_name, "%s_%02x", name, i + start_key); _save_key(temp_name, data + i * len, len, outbuf); } } From e578e09ff9483e44caaa13b44a5281e4b83b2a92 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 28 Oct 2019 09:56:38 -0600 Subject: [PATCH 037/166] v1.7.0: Titlekey save parsing, memory bugfixes --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6c33bb3..5aef471 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 6 -LPVERSION_BUGFX := 4 +LPVERSION_MINOR := 7 +LPVERSION_BUGFX := 0 ################################################################################ From fc8764392216168a6ce7b3554b61103e01d1e28c Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 31 Oct 2019 16:46:36 -0600 Subject: [PATCH 038/166] heap: Revert problematic size calculation Minor heap fragmentation was not worth preventing --- source/mem/heap.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/source/mem/heap.c b/source/mem/heap.c index 5efdbc2..fd46c16 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -83,7 +83,7 @@ static void _heap_free(heap_t *heap, u32 addr) hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); node->used = 0; node = heap->first; - while (1) + while (node) { if (!node->used) { @@ -95,14 +95,7 @@ static void _heap_free(heap_t *heap, u32 addr) node->next->prev = node->prev; } } - if (node->next) - node = node->next; - else - { - node->size = -1; - break; - } - + node = node->next; } } @@ -121,7 +114,7 @@ void *malloc(u32 size) void *calloc(u32 num, u32 size) { void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t)); - memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); + memset(res, 0, num * size); return res; } From aac874f7a3b26192bc3d58c97e425dc7fa6fdb24 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 31 Oct 2019 21:08:58 -0600 Subject: [PATCH 039/166] v1.7.1: Heap bugfix, add payload chainloading --- Makefile | 2 +- source/main.c | 457 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 323 insertions(+), 136 deletions(-) diff --git a/Makefile b/Makefile index 5aef471..cd2b95e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 7 -LPVERSION_BUGFX := 0 +LPVERSION_BUGFX := 1 ################################################################################ diff --git a/source/main.c b/source/main.c index 97a5755..5cd0a75 100644 --- a/source/main.c +++ b/source/main.c @@ -19,6 +19,7 @@ #include #include "config/config.h" +#include "config/ini.h" #include "gfx/di.h" #include "gfx/gfx.h" #include "gfx/tui.h" @@ -33,6 +34,8 @@ #include "storage/emummc.h" #include "storage/nx_emmc.h" #include "storage/sdmmc.h" +#include "utils/btn.h" +#include "utils/dirlist.h" #include "utils/sprintf.h" #include "utils/util.h" @@ -48,166 +51,348 @@ boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; bool sd_mount() { - if (sd_mounted) - return true; + if (sd_mounted) + return true; - if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) - { - EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); - } - else - { - int res = 0; - res = f_mount(&sd_fs, "sd:", 1); - if (res == FR_OK) - { - sd_mounted = 1; - return true; - } - else - { - EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); - } - } + if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) + { + EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); + } + else + { + int res = 0; + res = f_mount(&sd_fs, "sd:", 1); + if (res == FR_OK) + { + sd_mounted = 1; + return true; + } + else + { + EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); + } + } - return false; + return false; } void sd_unmount() { - if (sd_mounted) - { - f_mount(NULL, "sd:", 1); - sdmmc_storage_end(&sd_storage); - sd_mounted = false; - } + if (sd_mounted) + { + f_mount(NULL, "sd:", 1); + sdmmc_storage_end(&sd_storage); + sd_mounted = false; + } } void *sd_file_read(const char *path, u32 *fsize) { - FIL fp; - if (f_open(&fp, path, FA_READ) != FR_OK) - return NULL; + FIL fp; + if (f_open(&fp, path, FA_READ) != FR_OK) + return NULL; - u32 size = f_size(&fp); - if (fsize) - *fsize = size; + u32 size = f_size(&fp); + if (fsize) + *fsize = size; - void *buf = malloc(size); + void *buf = malloc(size); - if (f_read(&fp, buf, size, NULL) != FR_OK) - { - free(buf); - f_close(&fp); + if (f_read(&fp, buf, size, NULL) != FR_OK) + { + free(buf); + f_close(&fp); - return NULL; - } + return NULL; + } - f_close(&fp); + f_close(&fp); - return buf; + 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; - } + 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); + f_write(&fp, buf, size, NULL); + f_close(&fp); - return 0; + return 0; } // This is a safe and unused DRAM region for our payloads. #define RELOC_META_OFF 0x7C #define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_STACK 0x40007000 +#define PATCHED_RELOC_ENTRY 0x40010000 +#define EXT_PAYLOAD_ADDR 0xC03C0000 +#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define COREBOOT_ADDR (0xD0000000 - 0x100000) #define CBFS_DRAM_EN_ADDR 0x4003e000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { - memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); + memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); - volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); + volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); - relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); - relocator->stack = PATCHED_RELOC_STACK; - relocator->end = payload_dst + payload_size; - relocator->ep = payload_dst; + relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); + relocator->stack = PATCHED_RELOC_STACK; + relocator->end = payload_dst + payload_size; + relocator->ep = payload_dst; - if (payload_size == 0x7000) - { - memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock - *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; - } + if (payload_size == 0x7000) + { + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; + } +} + +int launch_payload(char *path) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + if (!path) + return 1; + + if (sd_mount()) + { + FIL fp; + if (f_open(&fp, path, FA_READ)) + { + EPRINTFARGS("Payload file is missing!\n(%s)", path); + sd_unmount(); + + return 1; + } + + // Read and copy the payload to our chosen address + void *buf; + u32 size = f_size(&fp); + + if (size < 0x30000) + buf = (void *)RCM_PAYLOAD_ADDR; + else + buf = (void *)COREBOOT_ADDR; + + if (f_read(&fp, buf, size, NULL)) + { + f_close(&fp); + sd_unmount(); + + return 1; + } + + f_close(&fp); + + sd_unmount(); + + if (size < 0x30000) + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + + reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); + } + else + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); + reconfig_hw_workaround(true, 0); + } + + // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); + + void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; + + // Launch our payload. + (*ext_payload_ptr)(); + } + + return 1; +} + +void launch_tools() +{ + u8 max_entries = 61; + char *filelist = NULL; + char *file_sec = NULL; + char *dir = NULL; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (sd_mount()) + { + dir = (char *)malloc(256); + + memcpy(dir, "sd:/bootloader/payloads", 24); + + filelist = dirlist(dir, NULL, false); + + u32 i = 0; + u32 i_off = 2; + + if (filelist) + { + // Build configuration menu. + u32 color_idx = 0; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + ments[0].color = colors[(color_idx++) % 6]; + ments[1].type = MENT_CHGLINE; + ments[1].color = colors[(color_idx++) % 6]; + if (!f_stat("sd:/atmosphere/reboot_payload.bin", NULL)) + { + ments[i_off].type = INI_CHOICE; + ments[i_off].caption = "reboot_payload.bin"; + ments[i_off].color = colors[(color_idx++) % 6]; + ments[i_off].data = "sd:/atmosphere/reboot_payload.bin"; + i_off++; + } + if (!f_stat("sd:/ReiNX.bin", NULL)) + { + ments[i_off].type = INI_CHOICE; + ments[i_off].caption = "ReiNX.bin"; + ments[i_off].color = colors[(color_idx++) % 6]; + ments[i_off].data = "sd:/ReiNX.bin"; + i_off++; + } + + while (true) + { + if (i > max_entries || !filelist[i * 256]) + break; + ments[i + i_off].type = INI_CHOICE; + ments[i + i_off].caption = &filelist[i * 256]; + ments[i + i_off].color = colors[(color_idx++) % 6]; + ments[i + i_off].data = &filelist[i * 256]; + + i++; + } + } + + if (i > 0) + { + memset(&ments[i + i_off], 0, sizeof(ment_t)); + menu_t menu = { ments, "Choose a file to launch", 0, 0 }; + + file_sec = (char *)tui_do_menu(&menu); + + if (!file_sec) + { + free(ments); + free(dir); + free(filelist); + sd_unmount(); + return; + } + } + else + EPRINTF("No payloads or modules found."); + + free(ments); + free(filelist); + } + else + { + free(ments); + goto out; + } + + if (file_sec) + { + if (memcmp("sd:/", file_sec, 4)) { + memcpy(dir + strlen(dir), "/", 2); + memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1); + } + else + memcpy(dir, file_sec, strlen(file_sec) + 1); + + if (launch_payload(dir)) + { + EPRINTF("Failed to launch payload."); + free(dir); + } + } + +out: + sd_unmount(); + free(dir); + + btn_wait(); } void dump_sysnand() { - h_cfg.emummc_force_disable = true; - b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; - dump_keys(); + h_cfg.emummc_force_disable = true; + b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); } void dump_emunand() { - if (h_cfg.emummc_force_disable) - return; - emu_cfg.enabled = 1; - b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; - dump_keys(); + if (h_cfg.emummc_force_disable) + return; + emu_cfg.enabled = 1; + b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); } ment_t ment_top[] = { - MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), - MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), - MDEF_CAPTION("---------------", COLOR_YELLOW), - MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN), - MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE), - MDEF_HANDLER("Power off", power_off, COLOR_VIOLET), - MDEF_END() + MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), + MDEF_CAPTION("---------------", COLOR_YELLOW), + MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), + MDEF_CAPTION("---------------", COLOR_BLUE), + MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_VIOLET), + MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_RED), + MDEF_HANDLER("Power off", power_off, COLOR_ORANGE), + MDEF_END() }; menu_t menu_top = { ment_top, NULL, 0, 0 }; void _get_key_generations(char *sysnand_label, char *emunand_label) { - sdmmc_t sdmmc; - sdmmc_storage_t storage; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); - sdmmc_storage_end(&storage); + sdmmc_t sdmmc; + sdmmc_storage_t storage; + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + sdmmc_storage_end(&storage); - if (pkg1_id) - sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); - ment_top[0].caption = sysnand_label; - if (h_cfg.emummc_force_disable) { - free(pkg1); - return; - } + if (pkg1_id) + sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + ment_top[0].caption = sysnand_label; + if (h_cfg.emummc_force_disable) { + free(pkg1); + return; + } - emummc_storage_init_mmc(&storage, &sdmmc); - memset(pkg1, 0, NX_EMMC_BLOCKSIZE); - emummc_storage_set_mmc_partition(&storage, 1); - emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); - pkg1_id = pkg1_identify(pkg1); - emummc_storage_end(&storage); + emummc_storage_init_mmc(&storage, &sdmmc); + memset(pkg1, 0, NX_EMMC_BLOCKSIZE); + emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + pkg1_id = pkg1_identify(pkg1); + emummc_storage_end(&storage); - if (pkg1_id) - sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); - free(pkg1); - ment_top[1].caption = emunand_label; + if (pkg1_id) + sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + free(pkg1); + ment_top[1].caption = emunand_label; } #define IPL_STACK_TOP 0x90010000 @@ -215,47 +400,49 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) { extern void pivot_stack(u32 stack_top); +// todo: chainload to reboot payload or payloads folder option? + void ipl_main() { - config_hw(); - pivot_stack(IPL_STACK_TOP); - heap_init(IPL_HEAP_START); + config_hw(); + pivot_stack(IPL_STACK_TOP); + heap_init(IPL_HEAP_START); - set_default_configuration(); + set_default_configuration(); - sd_mount(); - minerva_init(); - minerva_change_freq(FREQ_1600); + sd_mount(); + minerva_init(); + minerva_change_freq(FREQ_1600); - display_init(); - u32 *fb = display_init_framebuffer(); - gfx_init_ctxt(fb, 720, 1280, 720); - gfx_con_init(); - display_backlight_pwm_init(); + display_init(); + u32 *fb = display_init_framebuffer(); + gfx_init_ctxt(fb, 720, 1280, 720); + gfx_con_init(); + display_backlight_pwm_init(); - bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); + bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); - h_cfg.emummc_force_disable = emummc_load_cfg(); + h_cfg.emummc_force_disable = emummc_load_cfg(); - if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) - { - if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) - h_cfg.emummc_force_disable = true; - dump_keys(); - } + if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) + { + if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) + h_cfg.emummc_force_disable = true; + dump_keys(); + } - if (h_cfg.emummc_force_disable) - { - ment_top[1].type = MENT_CAPTION; - ment_top[1].color = 0xFF555555; - ment_top[1].handler = NULL; - } + if (h_cfg.emummc_force_disable) + { + ment_top[1].type = MENT_CAPTION; + ment_top[1].color = 0xFF555555; + ment_top[1].handler = NULL; + } - _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); + _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); - while (true) - tui_do_menu(&menu_top); + while (true) + tui_do_menu(&menu_top); - while (true) - bpmp_halt(); + while (true) + bpmp_halt(); } From 7a486e547e43d560ab75fed527db1f53fa46cd99 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 7 Dec 2019 15:41:42 -0700 Subject: [PATCH 040/166] se: Use descriptive defines --- source/sec/se.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/sec/se.c b/source/sec/se.c index bf76e16..3074b9e 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -296,7 +296,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s SE(SE_SPARE_0_REG_OFFSET) = 1; SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) | + SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB); _se_aes_ctr_set(ctr); u32 src_size_aligned = src_size & 0xFFFFFFF0; @@ -381,7 +382,9 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) _gf256_mul_x(key); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | 0x145; + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | + SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); se_aes_key_iv_clear(ks); u32 num_blocks = (src_size + 0xf) >> 4; From 0459e813cf22a0bedcf3d98df38642967df44ada Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 7 Dec 2019 17:01:16 -0700 Subject: [PATCH 041/166] keys: Protect against free-before-use of kip --- source/keys/keys.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index b9f9fe2..cb799bb 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -483,9 +483,11 @@ get_tsec: ; } } pkg2_done: - free(ki->kip1); + if (ki) { + free(ki->kip1); + free(ki); + } free(pkg2); - free(ki); u8 *rights_ids = NULL, *titlekeys = NULL; From a9595e58376c359e385f9fc931de7b63b626a820 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 8 Dec 2019 12:16:29 -0700 Subject: [PATCH 042/166] Add 9.1.0 support --- source/hos/pkg1.c | 1 + source/keys/key_sources.inl | 6 +++++- source/utils/types.h | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 878cfb9..e93ac0d 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -41,6 +41,7 @@ static const pkg1_id_t _pkg1_ids[] = { { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0 { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 + { "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.1.0 { NULL } //End. }; diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 7e2ab81..5b0f6b7 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -30,6 +30,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 + {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 }; static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = @@ -44,6 +45,7 @@ static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ + {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ }; //======================================Keys======================================// @@ -79,6 +81,7 @@ static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VER {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ + {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */ }; static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { @@ -88,7 +91,8 @@ static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */ + {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */ }; // from SPL diff --git a/source/utils/types.h b/source/utils/types.h index e5dcb22..ab6f35b 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -36,7 +36,8 @@ #define KB_FIRMWARE_VERSION_700 7 #define KB_FIRMWARE_VERSION_810 8 #define KB_FIRMWARE_VERSION_900 9 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_900 +#define KB_FIRMWARE_VERSION_910 10 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 #define HOS_PKG11_MAGIC 0x31314B50 From cdb29719e4c86299a650db77b102aa91f3573674 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 8 Dec 2019 12:28:52 -0700 Subject: [PATCH 043/166] keys: Improve unrecognized pkg1 messaging --- source/keys/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index cb799bb..f697fa3 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -150,7 +150,7 @@ void dump_keys() { emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { - EPRINTF("Unknown pkg1 version."); + EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); goto out_wait; } From b3a739592ea35d437df7ffcebde5fd139a395a19 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 8 Dec 2019 19:17:46 -0700 Subject: [PATCH 044/166] Merge hekate 5.1.0 changes --- common/memory_map.h | 87 +++++ source/config/config.c | 612 ++++++++++++++++++++++++++++++ source/config/config.h | 7 + source/config/ini.c | 8 +- source/config/ini.h | 2 +- source/gfx/di.c | 5 +- source/gfx/di.h | 5 +- source/gfx/di.inl | 8 +- source/hos/pkg2.c | 1 + source/keys/keys.c | 1 - source/libs/fatfs/diskio.c | 6 +- source/main.c | 4 +- source/mem/minerva.c | 21 +- source/mem/minerva.h | 6 +- source/mem/sdram.c | 243 ++++++++++-- source/mem/sdram_lp0_param_t210.h | 2 +- source/power/max17050.c | 9 +- source/power/max17050.h | 4 +- source/power/max77620.h | 18 +- source/power/max7762x.c | 25 +- source/sec/se.c | 38 +- source/sec/se_t210.h | 42 +- source/sec/tsec.c | 7 +- source/soc/bpmp.c | 27 +- source/soc/bpmp.h | 11 +- source/soc/clock.c | 29 +- source/soc/clock.h | 3 +- source/soc/cluster.c | 7 +- source/soc/fuse.c | 316 +++++++++++++++ source/soc/fuse.h | 6 + source/soc/hw_init.c | 5 +- source/soc/kfuse.c | 35 +- source/soc/kfuse.h | 2 +- source/soc/smmu.c | 2 +- source/soc/t210.h | 10 +- source/storage/nx_emmc.c | 6 +- source/storage/sd.h | 6 +- source/storage/sdmmc.c | 52 +-- source/storage/sdmmc.h | 2 +- source/storage/sdmmc_driver.c | 20 +- source/utils/btn.c | 21 +- source/utils/btn.h | 3 +- source/utils/dirlist.c | 10 +- source/utils/types.h | 1 + source/utils/util.c | 9 +- source/utils/util.h | 5 +- 46 files changed, 1525 insertions(+), 224 deletions(-) create mode 100644 common/memory_map.h diff --git a/common/memory_map.h b/common/memory_map.h new file mode 100644 index 0000000..271d9f7 --- /dev/null +++ b/common/memory_map.h @@ -0,0 +1,87 @@ +/* + * 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 . + */ + +#ifndef _MEMORY_MAP_H_ +#define _MEMORY_MAP_H_ + +//#define IPL_STACK_TOP 0x4003FF00 +/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ +/* --- IPL: 0x40003000 - 0x40028000 --- */ +#define IPL_LOAD_ADDR 0x40003000 +#define IPL_SZ_MAX 0x20000 // 128KB. +//#define IRAM_LIB_ADDR 0x4002B000 +#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. +#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32. + +/* --- DRAM START --- */ +#define DRAM_START 0x80000000 +/* 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 SDXC_BUF_ALIGNED 0xB6000000 +#define MIXD_BUF_ALIGNED 0xB7000000 +#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED +#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). +#define SDMMC_UPPER_BUFFER 0xB8000000 +#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. + +// Virtual disk / Chainloader buffers. +#define RAM_DISK_ADDR 0xC1000000 +#define RAM_DISK_SZ 0x20000000 +//#define DRAM_LIB_ADDR 0xE0000000 +/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. +/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */ + +// Nyx buffers. +#define NYX_STORAGE_ADDR 0xED000000 +#define NYX_RES_ADDR 0xEE000000 + +// Framebuffer addresses. +#define IPL_FB_ADDRESS 0xF0000000 +#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. +#define LOG_FB_ADDRESS 0xF0400000 +#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. +#define NYX_FB_ADDRESS 0xF0800000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. + +// Nyx LvGL buffers. +#define NYX_LV_VDB_ADR 0xF0C00000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. +#define NYX_LV_MEM_ADR 0xF1000000 +#define NYX_LV_MEM_SZ 0x8000000 + +// NX BIS driver sector cache. +#define NX_BIS_CACHE_ADDR 0xF9000000 +#define NX_BIS_CACHE_SZ 0x8800 +/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */ + +// #define EXT_PAYLOAD_ADDR 0xC03C0000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - 0x100000) + +// NYX +// #define EXT_PAYLOAD_ADDR 0xC0000000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - 0x100000) + +#endif diff --git a/source/config/config.c b/source/config/config.c index 2fa964b..38e5bcf 100644 --- a/source/config/config.c +++ b/source/config/config.c @@ -20,6 +20,7 @@ #include "config.h" #include "ini.h" #include "../gfx/gfx.h" +#include "../gfx/tui.h" #include "../libs/fatfs/ff.h" #include "../soc/t210.h" #include "../storage/sdmmc.h" @@ -52,3 +53,614 @@ void set_default_configuration() sd_power_cycle_time_start = 0xFFFFFFF; } +int create_config_entry() +{ + if (!sd_mount()) + return 1; + + char lbuf[32]; + FIL fp; + bool mainIniFound = false; + + LIST_INIT(ini_sections); + + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + mainIniFound = true; + else + { + u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); + if (res == FR_NO_FILE || res == FR_NO_PATH) + { + f_mkdir("bootloader"); + f_mkdir("bootloader/ini"); + f_mkdir("bootloader/payloads"); + f_mkdir("bootloader/sys"); + } + else + { + if (!res) + f_close(&fp); + return 1; + } + } + + if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return 1; + // Add config entry. + f_puts("[config]\nautoboot=", &fp); + itoa(h_cfg.autoboot, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); + itoa(h_cfg.autoboot_list, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbootwait=", &fp); + itoa(h_cfg.bootwait, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nverification=", &fp); + itoa(h_cfg.verification, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbacklight=", &fp); + itoa(h_cfg.backlight, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautohosoff=", &fp); + itoa(h_cfg.autohosoff, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautonogc=", &fp); + itoa(h_cfg.autonogc, lbuf, 10); + f_puts(lbuf, &fp); + if (h_cfg.brand) + { + f_puts("\nbrand=", &fp); + f_puts(h_cfg.brand, &fp); + } + if (h_cfg.tagline) + { + f_puts("\ntagline=", &fp); + f_puts(h_cfg.tagline, &fp); + } + f_puts("\n", &fp); + + if (mainIniFound) + { + // Re-construct existing entries. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + switch (ini_sec->type) + { + case INI_CHOICE: // Re-construct Boot entry [ ]. + f_puts("[", &fp); + f_puts(ini_sec->name, &fp); + f_puts("]\n", &fp); + // Re-construct boot entry's config. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + f_puts(kv->key, &fp); + f_puts("=", &fp); + f_puts(kv->val, &fp); + f_puts("\n", &fp); + } + break; + case INI_CAPTION: // Re-construct caption entry { }. + f_puts("{", &fp); + f_puts(ini_sec->name, &fp); + f_puts("}\n", &fp); + break; + case INI_NEWLINE: // Re-construct cosmetic newline \n. + f_puts("\n", &fp); + break; + case INI_COMMENT: // Re-construct comment entry #. + f_puts("#", &fp); + f_puts(ini_sec->name, &fp); + f_puts("\n", &fp); + break; + } + } + } + + f_close(&fp); + sd_unmount(); + + return 0; +} + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +static void _save_config() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (!create_config_entry()) + gfx_puts("\nConfiguration was saved!\n"); + else + EPRINTF("\nConfiguration saving failed!"); + gfx_puts("\nPress any key..."); +} + +static void _config_autoboot_list(void *ent) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) + boot_text[(i - 1) * 512] = ' '; + + else + boot_text[(i - 1) * 512] = '*'; + strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 1) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 1]; + i++; + + if ((i - 1) > max_entries) + break; + } + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 1; + _save_config(); + + ment_t *tmp = (ment_t *)ent; + tmp->data = NULL; + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); +} + +void config_autoboot() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (!h_cfg.autoboot) + ments[2].caption = "*Disable"; + else + ments[2].caption = " Disable"; + ments[2].data = &boot_values[0]; + + ments[3].type = MENT_HDLR_RE; + if (h_cfg.autoboot_list) + ments[3].caption = "*More configs..."; + else + ments[3].caption = " More configs..."; + ments[3].handler = _config_autoboot_list; + ments[3].data = (void *)0xCAFE; + + ments[4].type = MENT_CHGLINE; + + u32 i = 5; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) + boot_text[(i - 4) * 512] = ' '; + + else + boot_text[(i - 4) * 512] = '*'; + strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 4) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 4]; + i++; + + if ((i - 4) > max_entries) + break; + } + } + if (i < 6 && !h_cfg.autoboot_list) + { + ments[i].type = MENT_CAPTION; + ments[i].caption = "No main configurations found..."; + ments[i].color = 0xFFFFDD00; + i++; + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 0; + _save_config(); + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); + + if (temp_autoboot == NULL) + return; +} + +void config_bootdelay() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 delay_entries = 6; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); + u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); + char *delay_text = (char *)malloc(32 * delay_entries); + + for (u32 j = 0; j < delay_entries; j++) + delay_values[j] = j; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (h_cfg.bootwait) + ments[2].caption = " 0 seconds (Bootlogo disabled)"; + else + ments[2].caption = "*0 seconds (Bootlogo disabled)"; + ments[2].data = &delay_values[0]; + + u32 i = 0; + for (i = 1; i < delay_entries; i++) + { + if (h_cfg.bootwait != i) + delay_text[i * 32] = ' '; + else + delay_text[i * 32] = '*'; + delay_text[i * 32 + 1] = i + '0'; + strcpy(delay_text + i * 32 + 2, " seconds"); + + ments[i + 2].type = MENT_DATA; + ments[i + 2].caption = delay_text + i * 32; + ments[i + 2].data = &delay_values[i]; + } + + memset(&ments[i + 2], 0, sizeof(ment_t)); + menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; + + u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); + if (temp_bootwait != NULL) + { + h_cfg.bootwait = *(u32 *)temp_bootwait; + _save_config(); + } + + free(ments); + free(delay_values); + free(delay_text); + + if (temp_bootwait == NULL) + return; + 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() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 bri_entries = 11; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); + u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); + char *bri_text = (char *)malloc(8 * bri_entries); + + for (u32 j = 1; j < bri_entries; j++) + bri_values[j] = j * 10; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 0; + for (i = 1; i < bri_entries; i++) + { + if ((h_cfg.backlight / 20) != i) + bri_text[i * 32] = ' '; + else + bri_text[i * 32] = '*'; + + if (i < 10) + { + bri_text[i * 32 + 1] = i + '0'; + strcpy(bri_text + i * 32 + 2, "0%"); + } + else + strcpy(bri_text + i * 32 + 1, "100%"); + + ments[i + 1].type = MENT_DATA; + ments[i + 1].caption = bri_text + i * 32; + ments[i + 1].data = &bri_values[i]; + } + + memset(&ments[i + 1], 0, sizeof(ment_t)); + menu_t menu = {ments, "Backlight brightness", 0, 0}; + + u32 *temp_backlight = (u32 *)tui_do_menu(&menu); + if (temp_backlight != NULL) + { + h_cfg.backlight = (*(u32 *)temp_backlight) * 2; + _save_config(); + } + + free(ments); + free(bri_values); + free(bri_text); + + if (temp_backlight == NULL) + return; + btn_wait(); +} + +void config_auto_hos_poweroff() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); + u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); + + for (u32 j = 0; j < 3; j++) + { + hp_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &hp_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autohosoff == 1) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Enable"; + ments[4].caption = " Enable (No logo)"; + } + else if (h_cfg.autohosoff >= 2) + { + ments[2].caption = " Disable"; + ments[3].caption = " Enable"; + ments[4].caption = "*Enable (No logo)"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Enable"; + ments[4].caption = " Enable (No logo)"; + } + + memset(&ments[5], 0, sizeof(ment_t)); + menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; + + u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); + if (temp_autohosoff != NULL) + { + h_cfg.autohosoff = *(u32 *)temp_autohosoff; + _save_config(); + } + + free(ments); + free(hp_values); + + if (temp_autohosoff == NULL) + return; + btn_wait(); +} + +void config_nogc() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); + u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); + + for (u32 j = 0; j < 2; j++) + { + cb_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &cb_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autonogc) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Auto"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Auto"; + } + + memset(&ments[4], 0, sizeof(ment_t)); + menu_t menu = {ments, "No Gamecard", 0, 0}; + + u32 *temp_nogc = (u32 *)tui_do_menu(&menu); + if (temp_nogc != NULL) + { + h_cfg.autonogc = *(u32 *)temp_nogc; + _save_config(); + } + + free(ments); + free(cb_values); + + if (temp_nogc == NULL) + return; + btn_wait(); +} + +#pragma GCC pop_options diff --git a/source/config/config.h b/source/config/config.h index 1f6c36d..8cd34e1 100644 --- a/source/config/config.h +++ b/source/config/config.h @@ -46,5 +46,12 @@ typedef enum } hsysmodule_t; void set_default_configuration(); +int create_config_entry(); +void config_autoboot(); +void config_bootdelay(); +void config_verification(); +void config_backlight(); +void config_auto_hos_poweroff(); +void config_nogc(); #endif /* _CONFIG_H_ */ diff --git a/source/config/ini.c b/source/config/ini.c index f033994..e807aec 100644 --- a/source/config/ini.c +++ b/source/config/ini.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2019 CTCaer + * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -78,7 +78,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) char *filename = (char *)malloc(256); - memcpy(filename, ini_path, pathlen + 1); + strcpy(filename, ini_path); // Get all ini filenames. if (is_dir) @@ -89,7 +89,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) free(filename); return 0; } - memcpy(filename + pathlen, "/", 2); + strcpy(filename + pathlen, "/"); pathlen++; } @@ -100,7 +100,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) { if (filelist[k * 256]) { - memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1); + strcpy(filename + pathlen, &filelist[k * 256]); k++; } else diff --git a/source/config/ini.h b/source/config/ini.h index 318adf0..dffbe86 100644 --- a/source/config/ini.h +++ b/source/config/ini.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/gfx/di.c b/source/gfx/di.c index 1dcef3f..200d412 100644 --- a/source/gfx/di.c +++ b/source/gfx/di.c @@ -262,11 +262,12 @@ void display_color_screen(u32 color) u32 *display_init_framebuffer() { // Sanitize framebuffer area. - memset((u32 *)FB_ADDRESS, 0, 0x3C0000); + memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000); + // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); usleep(35000); - return (u32 *)FB_ADDRESS; + return (u32 *)IPL_FB_ADDRESS; } diff --git a/source/gfx/di.h b/source/gfx/di.h index 69d231a..ee796a7 100644 --- a/source/gfx/di.h +++ b/source/gfx/di.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,10 +18,9 @@ #ifndef _DI_H_ #define _DI_H_ +#include "../../common/memory_map.h" #include "../utils/types.h" -#define FB_ADDRESS 0xC0000000 - /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) diff --git a/source/gfx/di.inl b/source/gfx/di.inl index 58bf442..dd82899 100644 --- a/source/gfx/di.inl +++ b/source/gfx/di.inl @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (C) 2018 CTCaer +* Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -128,7 +128,7 @@ static const cfg_op_t _display_config_2[94] = { }; //DSI Init config. -static const cfg_op_t _display_config_3[61] = { +static const cfg_op_t _display_config_3[61] = { {DSI_WR_DATA, 0}, {DSI_INT_ENABLE, 0}, {DSI_INT_STATUS, 0}, @@ -415,7 +415,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_DISP_SYNC_WIDTH, 0x10048}, {DC_DISP_BACK_PORCH, 0x90048}, {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. + {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. /* End of Display timings */ {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, @@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = { {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {DC_WIN_BUFFER_CONTROL, 0}, {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address. + {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. {DC_WINBUF_ADDR_H_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WIN_WIN_OPTIONS, 0}, diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index 301fd4e..e745cbc 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -139,6 +139,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) memcpy(newKip, &hdr, sizeof(hdr)); newKipSize = dstDataPtr-(unsigned char*)(newKip); + free(ki->kip1); ki->kip1 = newKip; ki->size = newKipSize; diff --git a/source/keys/keys.c b/source/keys/keys.c index f697fa3..c5a27d3 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -484,7 +484,6 @@ get_tsec: ; } pkg2_done: if (ki) { - free(ki->kip1); free(ki); } free(pkg2); diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 75a1c1e..0dea450 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -24,15 +24,15 @@ /*-----------------------------------------------------------------------*/ #include + +#include "../../../common/memory_map.h" + #include "diskio.h" /* FatFs lower layer API */ #include "../../mem/heap.h" #include "../../sec/se.h" #include "../../storage/nx_emmc.h" #include "../../storage/sdmmc.h" -#define SDMMC_UPPER_BUFFER 0xB8000000 -#define DRAM_START 0x80000000 - extern sdmmc_storage_t sd_storage; extern sdmmc_storage_t storage; extern emmc_part_t *system_part; diff --git a/source/main.c b/source/main.c index 5cd0a75..4d3ee27 100644 --- a/source/main.c +++ b/source/main.c @@ -49,6 +49,8 @@ static bool sd_mounted; hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; +volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; + bool sd_mount() { if (sd_mounted) @@ -420,7 +422,7 @@ void ipl_main() gfx_con_init(); display_backlight_pwm_init(); - bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); h_cfg.emummc_force_disable = emummc_load_cfg(); diff --git a/source/mem/minerva.c b/source/mem/minerva.c index 2ac8516..6683053 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -26,7 +26,7 @@ #include "../soc/fuse.h" #include "../soc/t210.h" -volatile nyx_storage_t *nyx_str = (nyx_storage_t *)0xED000000; +extern volatile nyx_storage_t *nyx_str; void minerva_init() { @@ -34,8 +34,10 @@ void minerva_init() mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - // Set table to ram. - mtc_cfg->mtc_table = NULL; + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; + + mtc_cfg->init_done = MTC_NEW_MAGIC; mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); minerva_cfg = (void *)ep_addr; @@ -58,6 +60,15 @@ void minerva_init() minerva_cfg(mtc_cfg, NULL); mtc_cfg->rate_to = 1600000; minerva_cfg(mtc_cfg, NULL); + + // FSP WAR. + mtc_cfg->train_mode = OP_SWITCH; + mtc_cfg->rate_to = 800000; + minerva_cfg(mtc_cfg, NULL); + + // Switch to max. + mtc_cfg->rate_to = 1600000; + minerva_cfg(mtc_cfg, NULL); } void minerva_change_freq(minerva_freq_t freq) @@ -66,7 +77,7 @@ void minerva_change_freq(minerva_freq_t freq) return; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (minerva_cfg && (mtc_cfg->rate_from != freq)) + if (mtc_cfg->rate_from != freq) { mtc_cfg->rate_to = freq; mtc_cfg->train_mode = OP_SWITCH; @@ -80,7 +91,7 @@ void minerva_periodic_training() return; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (minerva_cfg && mtc_cfg->rate_from == FREQ_1600) + if (mtc_cfg->rate_from == FREQ_1600) { mtc_cfg->train_mode = OP_PERIODIC_TRAIN; minerva_cfg(mtc_cfg, NULL); diff --git a/source/mem/minerva.h b/source/mem/minerva.h index dd71658..f1edbaa 100644 --- a/source/mem/minerva.h +++ b/source/mem/minerva.h @@ -20,7 +20,10 @@ #include "mtc_table.h" #include "../utils/types.h" -#define EMC_PERIODIC_TRAIN_MS 100 +#define MTC_INIT_MAGIC 0x3043544D +#define MTC_NEW_MAGIC 0x5243544D + +#define EMC_PERIODIC_TRAIN_MS 250 typedef struct { @@ -35,6 +38,7 @@ typedef struct bool emc_2X_clk_src_is_pllmb; bool fsp_for_src_freq; bool train_ram_patterns; + bool init_done; } mtc_config_t; enum train_mode_t diff --git a/source/mem/sdram.c b/source/mem/sdram.c index db9637a..a9a26d3 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -16,17 +16,18 @@ * along with this program. If not, see . */ -#include "../soc/i2c.h" -#include "../soc/t210.h" #include "mc.h" #include "emc.h" #include "sdram_param_t210.h" -#include "../soc/pmc.h" -#include "../utils/util.h" -#include "../soc/fuse.h" +#include "../../common/memory_map.h" #include "../power/max77620.h" #include "../power/max7762x.h" #include "../soc/clock.h" +#include "../soc/fuse.h" +#include "../soc/i2c.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../utils/util.h" #define CONFIG_SDRAM_COMPRESS_CFG @@ -50,19 +51,31 @@ static u32 _get_sdram_id() static void _sdram_config(const sdram_params_t *params) { - PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF; + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; usleep(params->pmc_io_dpd3_req_wait); - u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000; - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000; + // Disable e_dpd_vttgen. + dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; usleep(params->pmc_io_dpd4_req_wait); - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF; + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; usleep(params->pmc_io_dpd4_req_wait); + PMC(APBDEV_PMC_WEAK_BIAS) = 0; usleep(1); + // Start clocks. CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; + + // u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); + // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; + // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); u32 wait_end = get_tmr_us() + 300; @@ -72,24 +85,35 @@ static void _sdram_config(const sdram_params_t *params) goto break_nosleep; } usleep(10); -break_nosleep: +break_nosleep: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); if (params->emc_clock_source_dll) CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; if (params->clear_clock2_mc1) CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; + + 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_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. + + // Set pad macros. EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; - EMC(EMC_TIMING_CONTROL) = 1; - usleep(1); + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(10); // Ensure the regulators settle. + + // Select EMC write mux. EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. if (params->emc_bct_spare2) *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; @@ -104,25 +128,40 @@ break_nosleep: EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; + + // Program brick mapping. EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1; EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED; + + // This is required to do any reads from the pad macros. EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0; EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1; EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2; EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3; + // Set swizzle for Rank 1. EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0; EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1; EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; + + // Patch 4 using BCT spare variables. if (params->emc_bct_spare6) *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Set pad controls. EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl; EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; + + // Program Autocal controls with shadowed register fields. EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2; EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; @@ -130,6 +169,7 @@ break_nosleep: EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6; EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; + EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; @@ -137,9 +177,11 @@ break_nosleep: EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; + EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; + EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0; EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; @@ -152,8 +194,10 @@ break_nosleep: EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1; EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40; EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; + EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd; EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F; EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; @@ -164,6 +208,7 @@ break_nosleep: EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode; EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + EMC(EMC_CFG_3) = params->emc_cfg3; EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; @@ -189,6 +234,7 @@ break_nosleep: EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0; EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1; EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; @@ -202,6 +248,7 @@ break_nosleep: EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4; EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2; @@ -214,6 +261,7 @@ break_nosleep: EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0; EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1; EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2; @@ -234,6 +282,7 @@ break_nosleep: EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1; EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2; EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0; EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1; EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; @@ -242,10 +291,17 @@ break_nosleep: EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0; EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1; EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2; + + // Common pad macro (cpm). EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; + + // Patch 3 using BCT spare variables. if (params->emc_bct_spare4) *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + // Initialize MC VPR settings. MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi; MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb; @@ -253,20 +309,32 @@ break_nosleep: MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1; MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0; MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1; + + // Program SDRAM geometry parameters. MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg; MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0; MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1; MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask; + + // Program bank swizzling. MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0; MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1; MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2; + + // Program external memory aperture (base and size). MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom; MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi; MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb; + + // Program MTS carveout (base and size). MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom; MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi; MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb; + + // Program the memory arbiter. MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg; MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req; MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl; @@ -295,21 +363,38 @@ break_nosleep: MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1; MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; MC(MC_DA_CONFIG0) = params->mc_da_cfg0; - MC(MC_TIMING_CONTROL) = 1; + + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + + // Program second-level clock enable overrides. MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0; EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1; EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2; + EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. if (params->emc_bct_spare8) *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + // Program EMC timing configuration. EMC(EMC_CFG_2) = params->emc_cfg2; EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe; EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1; @@ -354,9 +439,11 @@ break_nosleep: EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration; EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra; EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl; EMC(EMC_DBG) = params->emc_dbg; EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; EMC(EMC_ISSUE_QRST) = 0; EMC(EMC_QSAFE) = params->emc_qsafe; EMC(EMC_RDV) = params->emc_rdv; @@ -389,6 +476,8 @@ break_nosleep: EMC(EMC_ODT_WRITE) = params->emc_odt_write; EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll; EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD; EMC(EMC_CFG_RSV) = params->emc_cfg_rsv; EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1; @@ -396,70 +485,104 @@ break_nosleep: EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; + + // Set pipe bypass enable bits before sending any DRAM commands. EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // Patch BootROM. if (params->boot_rom_patch_control & (1 << 31)) { *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; - MC(MC_TIMING_CONTROL) = 1; + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. } - PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000; + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; usleep(params->pmc_io_dpd3_req_wait); + + // Set autocal interval if not configured. if (!params->emc_auto_cal_interval) EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2; + + // ZQ CAL setup (not actually issuing ZQ CAL now). if (params->emc_zcal_warm_cold_boot_enables & 1) { if (params->memory_type == 2) - EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; if (params->memory_type == 3) { EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; } } - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; usleep(params->pmc_ddr_ctrl_wait); - if (params->memory_type == 2) + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + if (params->memory_type == 2 || params->memory_type == 3) { - EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; - usleep(params->emc_pin_extra_wait + 500); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); } + if (params->memory_type == 3) - { - EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); - usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; usleep(params->emc_pin_extra_wait + 2000); - } - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101; + else if (params->memory_type == 2) + usleep(params->emc_pin_extra_wait + 500); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); usleep(params->emc_pin_program_wait); + + // Send NOP (trigger just needs to be non-zero). if (params->memory_type != 3) EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; + + // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. if (params->memory_type == 1) usleep(params->emc_pin_extra_wait + 200); + + // Init zq calibration, if (params->memory_type == 3) { + // Patch 6 using BCT spare variables. if (params->emc_bct_spare10) *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. EMC(EMC_MRW2) = params->emc_mrw2; EMC(EMC_MRW) = params->emc_mrw1; EMC(EMC_MRW3) = params->emc_mrw3; EMC(EMC_MRW4) = params->emc_mrw4; EMC(EMC_MRW6) = params->emc_mrw6; EMC(EMC_MRW14) = params->emc_mrw14; + EMC(EMC_MRW8) = params->emc_mrw8; EMC(EMC_MRW12) = params->emc_mrw12; EMC(EMC_MRW9) = params->emc_mrw9; EMC(EMC_MRW13) = params->emc_mrw13; + if (params->emc_zcal_warm_cold_boot_enables & 1) { + // Issue ZQCAL start, device 0. EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. if (!(params->emc_dev_select & 2)) { EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; @@ -468,42 +591,64 @@ break_nosleep: } } } + + // Set package and DPD pad control. PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). if (params->memory_type - 1 <= 2) { EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; } + + // Patch 7 using BCT spare variables. if (params->emc_bct_spare12) *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + if (params->emc_extra_refresh_num) - EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30); + EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; + + // Enable refresh. EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; EMC(EMC_CFG) = params->emc_cfg; EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq; EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd; EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; + + // Write addr swizzle lock bit. EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. + + // Enable EMC pipe clock gating. EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; - SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16); + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); + + // Lock carveouts per BCT cfg. MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; - MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers. + + //Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; } sdram_params_t *sdram_get_params() { - //TODO: sdram_id should be in [0, 7]. - #ifdef CONFIG_SDRAM_COMPRESS_CFG - u8 *buf = (u8 *)0x40030000; + u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; #else @@ -535,7 +680,17 @@ sdram_params_t *sdram_get_params_patched() // Disable Warmboot signature check. sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); +/* + // Disable SBK lock. + sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); + sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); + // Disable bootrom read lock. + sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); + sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); + sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); + sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); +*/ return sdram_params; } @@ -544,16 +699,24 @@ void sdram_init() //TODO: sdram_id should be in [0,4]. const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); + // Set DRAM voltage. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage. + max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); + // VDDP Select. PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; usleep(params->pmc_vddp_sel_wait); + + // Set DDR pad voltage. PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); + + // Turn on MEM IO Power. PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power; PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + // Patch 1 using BCT spare variables if (params->emc_bct_spare0) *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; diff --git a/source/mem/sdram_lp0_param_t210.h b/source/mem/sdram_lp0_param_t210.h index 7f44f1d..9028990 100644 --- a/source/mem/sdram_lp0_param_t210.h +++ b/source/mem/sdram_lp0_param_t210.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/power/max17050.c b/source/power/max17050.c index 227f76b..635a437 100644 --- a/source/power/max17050.c +++ b/source/power/max17050.c @@ -1,9 +1,9 @@ /* * Fuel gauge driver for Nintendo Switch's Maxim 17050 * - * Copyright (C) 2011 Samsung Electronics + * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * 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 @@ -43,6 +43,9 @@ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ +#pragma GCC push_options +#pragma GCC optimize ("Os") + int max17050_get_property(enum MAX17050_reg reg, int *value) { u16 data; @@ -264,3 +267,5 @@ int max17050_fix_configuration() return 0; } + +#pragma GCC pop_options \ No newline at end of file diff --git a/source/power/max17050.h b/source/power/max17050.h index 2196b80..e4c8acf 100644 --- a/source/power/max17050.h +++ b/source/power/max17050.h @@ -2,9 +2,9 @@ * Fuel gauge driver for Nintendo Switch's Maxim 17050 * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. * - * Copyright (C) 2011 Samsung Electronics + * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * 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 diff --git a/source/power/max77620.h b/source/power/max77620.h index 479661d..26ea855 100644 --- a/source/power/max77620.h +++ b/source/power/max77620.h @@ -1,7 +1,7 @@ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * - * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it @@ -19,9 +19,19 @@ #define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) #define MAX77620_CNFGGLBL1_MPPLD (1 << 6) #define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4) -#define MAX77620_CNFGGLBL1_LBDAC 0x0E -#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E +#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) #define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) #define MAX77620_REG_CNFGGLBL2 0x01 diff --git a/source/power/max7762x.c b/source/power/max7762x.c index 2c8cff4..0e7a6b5 100644 --- a/source/power/max7762x.c +++ b/source/power/max7762x.c @@ -64,6 +64,16 @@ static const max77620_regulator_t _pmic_regulators[] = { { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } }; +static void _max77620_try_set_reg(u8 reg, u8 val) +{ + u8 tmp; + do + { + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); + tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); + } while (val != tmp); +} + int max77620_regulator_get_status(u32 id) { if (id > REGULATOR_MAX) @@ -83,7 +93,7 @@ int max77620_regulator_config_fps(u32 id) const max77620_regulator_t *reg = &_pmic_regulators[id]; - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, + _max77620_try_set_reg(reg->fps_addr, (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); return 1; @@ -102,7 +112,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); + _max77620_try_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -121,7 +131,7 @@ int max77620_regulator_enable(u32 id, int enable) val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); else val &= ~reg->enable_mask; - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val); + _max77620_try_set_reg(addr, val); usleep(1000); return 1; @@ -139,7 +149,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); + _max77620_try_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -155,11 +165,12 @@ void max77620_config_default() if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) max77620_regulator_enable(i, 1); } - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4); + _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); } void max77620_low_battery_monitor_config() { - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N); + _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, + MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/source/sec/se.c b/source/sec/se.c index 3074b9e..7416d38 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -86,8 +86,8 @@ static int _se_wait() while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET))) ; if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) || - SE(SE_STATUS_0) & 3 || - SE(SE_ERR_STATUS_0) != 0) + SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN || + SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) return 0; return 1; } @@ -111,12 +111,12 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); int res = _se_wait(); - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); return res; } @@ -148,9 +148,11 @@ static void _se_aes_ctr_set(void *ctr) void se_rsa_acc_ctrl(u32 rs, u32 flags) { - if (flags & 0x7F) - SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7; - if (flags & 0x80) + if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = + ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | + ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); + if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); } @@ -216,9 +218,9 @@ int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_siz void se_key_acc_ctrl(u32 ks, u32 flags) { - if (flags & 0x7F) + if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; - if (flags & 0x80) + if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); } @@ -424,15 +426,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) int res; // Setup config for SHA256, size = BITS(src_size). SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_ENABLE; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0; + SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH; + SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; // Trigger the operation. res = _se_execute(OP_START, NULL, 0, src, src_size); diff --git a/source/sec/se_t210.h b/source/sec/se_t210.h index 7d93099..3b610bc 100644 --- a/source/sec/se_t210.h +++ b/source/sec/se_t210.h @@ -36,6 +36,8 @@ #define SE_SECURITY_0 0x000 #define SE_KEY_SCHED_READ_SHIFT 3 +#define SE_TZRAM_SECURITY_0 0x004 + #define SE_CONFIG_REG_OFFSET 0x014 #define SE_CONFIG_ENC_ALG_SHIFT 12 #define SE_CONFIG_DEC_ALG_SHIFT 8 @@ -209,8 +211,12 @@ #define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT) #define SE_INT_ERROR_SHIFT 16 #define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT) + #define SE_STATUS_0 0x800 +#define SE_STATUS_0_STATE_WAIT_IN 3 + #define SE_ERR_STATUS_0 0x804 +#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 #define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 @@ -231,11 +237,17 @@ #define SE_SPARE_0_REG_OFFSET 0x80c #define SE_SHA_CONFIG_REG_OFFSET 0x200 -#define SHA_INIT_DISABLE 0 -#define SHA_INIT_ENABLE 1 +#define SHA_CONTINUE 0 +#define SHA_INIT_HASH 1 -#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204 -#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214 +#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 +#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 +#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C +#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 +#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 +#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 +#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C +#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 #define SE_HASH_RESULT_REG_COUNT 16 #define SE_HASH_RESULT_REG_OFFSET 0x030 @@ -254,13 +266,24 @@ TEGRA_SE_RNG_DT_SIZE) #define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16 -#define TEGRA_SE_RSA512_DIGEST_SIZE 64 +#define TEGRA_SE_RSA512_DIGEST_SIZE 64 #define TEGRA_SE_RSA1024_DIGEST_SIZE 128 #define TEGRA_SE_RSA1536_DIGEST_SIZE 192 #define TEGRA_SE_RSA2048_DIGEST_SIZE 256 #define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280 +#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + #define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 +#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) +#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F + #define SE_KEY_READ_DISABLE_SHIFT 0 #define SE_KEY_UPDATE_DISABLE_SHIFT 1 @@ -312,7 +335,16 @@ #define TEGRA_SE_RSA_KEYSLOT_COUNT 2 #define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C +#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + #define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F #define SE_RSA_KEYTABLE_ADDR 0x420 #define SE_RSA_KEYTABLE_DATA 0x424 diff --git a/source/sec/tsec.c b/source/sec/tsec.c index e07ca83..17cd623 100644 --- a/source/sec/tsec.c +++ b/source/sec/tsec.c @@ -23,6 +23,7 @@ #include "../sec/se_t210.h" #include "../soc/bpmp.h" #include "../soc/clock.h" +#include "../soc/kfuse.h" #include "../soc/smmu.h" #include "../soc/t210.h" #include "../mem/heap.h" @@ -77,6 +78,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) clock_enable_sor1(); clock_enable_kfuse(); + kfuse_wait_ready(); + //Configure Falcon. TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_IRQMSET) = @@ -208,7 +211,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) res = -6; smmu_deinit_for_tsec(); - goto out; + goto out_free; } // Give some extra time to make sure PKG1.1 is decrypted. @@ -278,7 +281,7 @@ out:; clock_disable_sor_safe(); clock_disable_tsec(); bpmp_mmu_enable(); - bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); return res; } diff --git a/source/soc/bpmp.c b/source/soc/bpmp.c index 3d6091d..94ce6d5 100644 --- a/source/soc/bpmp.c +++ b/source/soc/bpmp.c @@ -19,6 +19,7 @@ #include "bpmp.h" #include "clock.h" #include "t210.h" +#include "../../common/memory_map.h" #include "../utils/util.h" #define BPMP_CACHE_CONFIG 0x0 @@ -74,13 +75,13 @@ bpmp_mmu_entry_t mmu_entries[] = { - { 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, - { IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } + { DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, + { IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } }; -void bpmp_mmu_maintenance(u32 op) +void bpmp_mmu_maintenance(u32 op, bool force) { - if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) + if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) return; BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE; @@ -132,13 +133,13 @@ void bpmp_mmu_enable() BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; // Invalidate cache. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); // Enable cache. BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR; // HW bug. Invalidate cache again. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); } void bpmp_mmu_disable() @@ -147,21 +148,19 @@ void bpmp_mmu_disable() return; // Clean and invalidate cache. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); // Disable cache. BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; - - // HW bug. Invalidate cache again. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY); } const u8 pllc4_divn[] = { 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. - 85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB. - 90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB. - 94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz APB. - //95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB. + 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. + 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. + 92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB. + // Do not use for public releases! + //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. }; bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; diff --git a/source/soc/bpmp.h b/source/soc/bpmp.h index b45ab7a..4c1155e 100644 --- a/source/soc/bpmp.h +++ b/source/soc/bpmp.h @@ -36,13 +36,16 @@ typedef struct _bpmp_mmu_entry_t typedef enum { BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB. - BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB. - BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB. - BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB. + BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB. + BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB. + BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB. + //BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB. BPMP_CLK_MAX } bpmp_freq_t; -void bpmp_mmu_maintenance(u32 op); +#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST + +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_enable(); void bpmp_mmu_disable(); diff --git a/source/soc/clock.c b/source/soc/clock.c index 0726748..dda6d4b 100644 --- a/source/soc/clock.c +++ b/source/soc/clock.c @@ -15,7 +15,6 @@ */ #include "../soc/clock.h" -#include "../soc/kfuse.h" #include "../soc/t210.h" #include "../utils/util.h" #include "../storage/sdmmc.h" @@ -30,13 +29,14 @@ 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 } }; +//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0 FM_DIV: 26. 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, 6, 0 }, // 0, 19 }, // 100KHz -/* I2C2 */ { 0 }, -/* I2C3 */ { 0 }, -/* I2C4 */ { 0 }, -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 6, 0 }, // 0, 4 }, // 400KHz -/* I2C6 */ { 0 } +/* 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 +/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz +/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz +/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz +/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz }; static clock_t _clock_se = { @@ -74,7 +74,7 @@ static clock_t _clock_coresight = { }; 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 // Freference: 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. }; void clock_enable(const clock_t *clk) @@ -88,6 +88,8 @@ void clock_enable(const clock_t *clk) CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); // Enable. CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); + usleep(2); + // Take clock off reset. CLOCK(clk->reset) &= ~(1 << clk->index); } @@ -189,7 +191,6 @@ void clock_enable_kfuse() usleep(10); CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; usleep(20); - kfuse_wait_ready(); } void clock_disable_kfuse() @@ -368,7 +369,7 @@ static void _clock_sdmmc_clear_enable(u32 id) static u32 _clock_sdmmc_table[8] = { 0 }; #define PLLP_OUT0 0x0 -static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) +static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) { u32 divisor = 0; u32 source = PLLP_OUT0; @@ -416,6 +417,7 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) _clock_sdmmc_table[2 * id] = val; _clock_sdmmc_table[2 * id + 1] = *pout; + // Set SDMMC clock. switch (id) { case SDMMC_1: @@ -446,15 +448,16 @@ void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_source_inner(pout, id, val); + _clock_sdmmc_config_clock_host(pout, id, val); if (is_enabled) _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); } } -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type) +void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) { + // Get Card clock divisor. switch (type) { case 0: @@ -515,7 +518,7 @@ void clock_sdmmc_enable(u32 id, u32 val) if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(id); _clock_sdmmc_set_reset(id); - _clock_sdmmc_config_clock_source_inner(&div, id, val); + _clock_sdmmc_config_clock_host(&div, id, val); _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); usleep((100000 + div - 1) / div); diff --git a/source/soc/clock.h b/source/soc/clock.h index db7a974..ce6a81d 100644 --- a/source/soc/clock.h +++ b/source/soc/clock.h @@ -104,6 +104,7 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 #define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 #define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C +#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 #define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 #define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 #define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 @@ -181,7 +182,7 @@ void clock_disable_coresight(); void clock_enable_pwm(); void clock_disable_pwm(); void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type); +void clock_sdmmc_get_card_clock_div(u32 *pout, 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_disable(u32 id); diff --git a/source/soc/cluster.c b/source/soc/cluster.c index 0791d36..79538ed 100644 --- a/source/soc/cluster.c +++ b/source/soc/cluster.c @@ -80,9 +80,9 @@ void cluster_boot_cpu0(u32 entry) _cluster_enable_power(); - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. usleep(2); CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02; CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02; @@ -127,6 +127,9 @@ void cluster_boot_cpu0(u32 entry) SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; (void)SB(SB_CSR); + // Tighten up the security aperture. + // MC(MC_TZ_SECURITY_CTRL) = 1; + // Clear MSELECT reset. CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; // Clear NONCPU reset. diff --git a/source/soc/fuse.c b/source/soc/fuse.c index c53389e..04d3612 100644 --- a/source/soc/fuse.c +++ b/source/soc/fuse.c @@ -22,6 +22,34 @@ #include "../soc/fuse.h" #include "../soc/t210.h" +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) + +static const u32 evp_thunk_template[] = { + 0xe92d0007, // STMFD SP!, {R0-R2} + 0xe1a0200e, // MOV R2, LR + 0xe2422002, // SUB R2, R2, #2 + 0xe5922000, // LDR R2, [R2] + 0xe20220ff, // AND R2, R2, #0xFF + 0xe1a02082, // MOV R2, R2,LSL#1 + 0xe59f001c, // LDR R0, =evp_thunk_template + 0xe59f101c, // LDR R1, =thunk_end + 0xe0411000, // SUB R1, R1, R0 + 0xe59f0018, // LDR R0, =iram_evp_thunks + 0xe0800001, // ADD R0, R0, R1 + 0xe0822000, // ADD R2, R2, R0 + 0xe3822001, // ORR R2, R2, #1 + 0xe8bd0003, // LDMFD SP!, {R0,R1} + 0xe12fff12, // BX R2 + 0x001007b0, // off_1007EC DCD evp_thunk_template + 0x001007f8, // off_1007F0 DCD thunk_end + 0x40004c30, // off_1007F4 DCD iram_evp_thunks + // thunk_end is here +}; +static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); + +// treated as 12bit values +static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; + void fuse_disable_program() { FUSE(FUSE_DISABLEREGPROGRAM) = 1; @@ -31,3 +59,291 @@ u32 fuse_read_odm(u32 idx) { return FUSE(FUSE_RESERVED_ODMX(idx)); } + +void fuse_wait_idle() +{ + u32 ctrl; + do + { + ctrl = FUSE(FUSE_CTRL); + } while (((ctrl >> 16) & 0x1f) != 4); +} + +u32 fuse_read(u32 addr) +{ + FUSE(FUSE_ADDR) = addr; + FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; + fuse_wait_idle(); + return FUSE(FUSE_RDATA); +} + +void fuse_read_array(u32 *words) +{ + for (u32 i = 0; i < 192; i++) + words[i] = fuse_read(i); +} + +static u32 _parity32_even(u32 *words, u32 count) +{ + u32 acc = words[0]; + for (u32 i = 1; i < count; i++) + { + acc ^= words[i]; + } + u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; + u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; + u32 x = hi ^ lo; + lo = ((x & 0xf) ^ (x >> 4)) & 3; + hi = ((x & 0xf) ^ (x >> 4)) >> 2; + x = hi ^ lo; + + return (x & 1) ^ (x >> 1); +} + +static int _patch_hash_one(u32 *word) +{ + u32 bits20_31 = *word & 0xfff00000; + u32 parity_bit = _parity32_even(&bits20_31, 1); + u32 hash = 0; + for (u32 i = 0; i < 12; i++) + { + if (*word & (1 << (20 + i))) + { + hash ^= hash_vals[i]; + } + } + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + *word ^= 1 << 24; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) + { + if (hash_vals[i] == hash) + { + *word ^= 1 << (20 + i); + return 1; + } + } + return 2; +} + +static int _patch_hash_multi(u32 *words, u32 count) +{ + u32 parity_bit = _parity32_even(words, count); + u32 bits0_14 = words[0] & 0x7fff; + u32 bit15 = words[0] & 0x8000; + u32 bits16_19 = words[0] & 0xf0000; + + u32 hash = 0; + words[0] = bits16_19; + for (u32 i = 0; i < count; i++) + { + u32 w = words[i]; + if (w) + { + for (u32 bitpos = 0; bitpos < 32; bitpos++) + { + if ((w >> bitpos) & 1) + { + hash ^= 0x4000 + i * 32 + bitpos; + } + } + } + } + hash ^= bits0_14; + // stupid but this is what original code does. + // equivalent to original words[0] &= 0xfff00000 + words[0] = bits16_19 ^ bit15 ^ bits0_14; + + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + words[0] ^= 0x8000; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + u32 bitcount = hash - 0x4000; + if (bitcount < 16 || bitcount >= count * 32) + { + u32 num_set = 0; + for (u32 bitpos = 0; bitpos < 15; bitpos++) + { + if ((hash >> bitpos) & 1) + { + num_set++; + } + } + if (num_set != 1) + { + return 2; + } + words[0] ^= hash; + return 1; + } + words[bitcount / 32] ^= 1 << (hash & 0x1f); + return 1; +} + +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + if (ipatch_count) + { + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = words[i + 1]; + u32 addr = (word >> 16) * 2; + u32 data = word & 0xFFFF; + + ipatch(addr, data); + } + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + int evp_thunk_written = 0; + void *evp_thunk_dst_addr = 0; + + memset(iram_evp_thunks, 0, *iram_evp_thunks_len); + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + u32 insn_count = word_count - ipatch_count - 1; + if (insn_count) + { + if (!evp_thunk_written) + { + evp_thunk_dst_addr = (void *)iram_evp_thunks; + + memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); + evp_thunk_dst_addr += evp_thunk_template_len; + evp_thunk_written = 1; + *iram_evp_thunks_len = evp_thunk_template_len; + + //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); + } + + u32 thunk_patch_len = insn_count * sizeof(u32); + memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len); + evp_thunk_dst_addr += thunk_patch_len; + *iram_evp_thunks_len += thunk_patch_len; + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +bool fuse_check_patched_rcm() +{ + // Check if XUSB in use. + if (FUSE(FUSE_RESERVED_SW) & (1<<7)) + return true; + + // Check if RCM is ipatched. + u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; + u32 word_addr = 191; + + while (word_count) + { + u32 word0 = fuse_read(word_addr); + u32 ipatch_count = (word0 >> 16) & 0xF; + + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = fuse_read(word_addr - (i + 1)); + u32 addr = (word >> 16) * 2; + if (addr == 0x769A) + return true; + } + + word_addr -= word_count; + word_count = word0 >> 25; + } + + return false; +} diff --git a/source/soc/fuse.h b/source/soc/fuse.h index 0748936..9240b04 100644 --- a/source/soc/fuse.h +++ b/source/soc/fuse.h @@ -54,6 +54,7 @@ #define FUSE_PRIVATE_KEY3 0x1B0 #define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_RESERVED_SW 0x1C0 +#define FUSE_SKU_DIRECT_CONFIG 0x1F4 #define FUSE_OPT_VENDOR_CODE 0x200 #define FUSE_OPT_FAB_CODE 0x204 #define FUSE_OPT_LOT_CODE_0 0x208 @@ -74,5 +75,10 @@ void fuse_disable_program(); u32 fuse_read_odm(u32 idx); +void fuse_wait_idle(); +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); +void fuse_read_array(u32 *words); +bool fuse_check_patched_rcm(); #endif diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index e343fd0..9f0e900 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -219,7 +219,7 @@ void _config_regulators() { i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, - (1 << 6) | (1 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); @@ -257,7 +257,7 @@ void _config_regulators() MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - // Disable low battery shutdown monitor. + // Enable low battery shutdown monitor for < 2800mV. max77620_low_battery_monitor_config(); } @@ -274,6 +274,7 @@ void config_hw() // Enable fuse clock. clock_enable_fuse(true); + // Disable fuse programming. fuse_disable_program(); diff --git a/source/soc/kfuse.c b/source/soc/kfuse.c index 52f188f..f2fde5a 100644 --- a/source/soc/kfuse.c +++ b/source/soc/kfuse.c @@ -17,7 +17,21 @@ #include "../soc/kfuse.h" #include "../soc/clock.h" #include "../soc/t210.h" -#include "../utils/util.h" + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +int kfuse_wait_ready() +{ + // Wait for KFUSE to finish init and verification of data. + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + ; + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + return 0; + + return 1; +} int kfuse_read(u32 *buf) { @@ -25,10 +39,7 @@ int kfuse_read(u32 *buf) clock_enable_kfuse(); - while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) - ; - - if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + if (!kfuse_wait_ready()) goto out; KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; @@ -42,16 +53,4 @@ out:; return res; } -int kfuse_wait_ready() -{ - // Wait for KFUSE to finish init and verification of data. - while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) - { - usleep(500); - } - - if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) - return 0; - - return 1; -} +#pragma GCC pop_options diff --git a/source/soc/kfuse.h b/source/soc/kfuse.h index 3824eb8..a535803 100644 --- a/source/soc/kfuse.h +++ b/source/soc/kfuse.h @@ -36,7 +36,7 @@ #define KFUSE_NUM_WORDS 144 -int kfuse_read(u32 *buf); int kfuse_wait_ready(); +int kfuse_read(u32 *buf); #endif diff --git a/source/soc/smmu.c b/source/soc/smmu.c index 5aceaa4..fb096d4 100644 --- a/source/soc/smmu.c +++ b/source/soc/smmu.c @@ -106,7 +106,7 @@ bool smmu_is_used() void smmu_exit() { - *(uint32_t *)(smmu_payload + 0x14) = _NOP(); + *(u32 *)(smmu_payload + 0x14) = _NOP(); } u32 *smmu_init_domain4(u32 dev_base, u32 asid) diff --git a/source/soc/t210.h b/source/soc/t210.h index ea83dbc..85e42f4 100644 --- a/source/soc/t210.h +++ b/source/soc/t210.h @@ -108,6 +108,14 @@ /*! EVP registers. */ #define EVP_CPU_RESET_VECTOR 0x100 +#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 /*! Misc registers. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 @@ -208,7 +216,7 @@ #define HALT_COP_JTAG (1 << 28) #define HALT_COP_WAIT_EVENT (1 << 30) #define HALT_COP_WAIT_IRQ (1 << 31) -#define HALT_COP_MAX_CNT 0xFF +#define HALT_COP_MAX_CNT 0xFF #define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 #define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 #define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index 8f03848..c35177e 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -36,9 +36,9 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) part->lba_end = ent->lba_end; part->attrs = ent->attrs; - //HACK - for (u32 j = 0; j < 36; j++) - part->name[j] = ent->name[j]; + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. + for (u32 i = 0; i < 36; i++) + part->name[i] = ent->name[i]; part->name[36] = 0; list_append(gpt, &part->link); diff --git a/source/storage/sd.h b/source/storage/sd.h index c3bf82b..fafd322 100644 --- a/source/storage/sd.h +++ b/source/storage/sd.h @@ -1,8 +1,8 @@ /* * include/linux/mmc/sd.h * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. - * Copyright (C) 2018 CTCaer + * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (c) 2018 CTCaer * * 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 @@ -40,7 +40,9 @@ #define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ #define SD_OCR_XPC (1 << 28) /* SDXC power control */ #define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ +#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ #define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ /* * SD_SWITCH argument format: diff --git a/source/storage/sdmmc.c b/source/storage/sdmmc.c index 814556d..d75e609 100644 --- a/source/storage/sdmmc.c +++ b/source/storage/sdmmc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2019 CTCaer + * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,7 @@ #include "sdmmc.h" #include "mmc.h" #include "sd.h" +#include "../../common/memory_map.h" #include "../gfx/gfx.h" #include "../mem/heap.h" #include "../utils/util.h" @@ -220,10 +221,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u switch (power) { case SDMMC_POWER_1_8: - arg = 0x40000080; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_18; break; case SDMMC_POWER_3_3: - arg = 0x403F8000; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_27_34; break; default: return 0; @@ -248,7 +249,7 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) if (cond & MMC_CARD_BUSY) { - if (cond & 0x40000000) + if (cond & SD_OCR_CCS) storage->has_sector_access = 1; return 1; @@ -569,7 +570,7 @@ DPRINTF("[MMC] BKOPS disabled\n"); if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; -DPRINTF("[MMC] succesfully switched to highspeed mode\n"); +DPRINTF("[MMC] succesfully switched to HS mode\n"); sdmmc_sd_clock_ctrl(storage->sdmmc, 1); @@ -819,17 +820,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) switch (pwr) { case SD_SET_CURRENT_LIMIT_800: -DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] power limit raised to 800mA\n"); break; case SD_SET_CURRENT_LIMIT_600: -DPRINTF("[SD] Power limit raised to 600mA\n"); +DPRINTF("[SD] power limit raised to 600mA\n"); break; case SD_SET_CURRENT_LIMIT_400: -DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] power limit raised to 800mA\n"); break; default: case SD_SET_CURRENT_LIMIT_200: -DPRINTF("[SD] Power limit defaulted to 200mA\n"); +DPRINTF("[SD] power limit defaulted to 200mA\n"); break; } } @@ -857,7 +858,7 @@ DPRINTF("[SD] SD supports selected (U)HS mode\n"); return 1; } -int _sd_storage_enable_highspeed_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); @@ -878,7 +879,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 { type = 11; hs_type = UHS_SDR104_BUS_SPEED; -DPRINTF("[SD] Bus speed set to SDR104\n"); +DPRINTF("[SD] bus speed set to SDR104\n"); storage->csd.busspeed = 104; break; } @@ -887,7 +888,7 @@ DPRINTF("[SD] Bus speed set to SDR104\n"); { type = 10; hs_type = UHS_SDR50_BUS_SPEED; -DPRINTF("[SD] Bus speed set to SDR50\n"); +DPRINTF("[SD] bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } @@ -896,7 +897,7 @@ DPRINTF("[SD] Bus speed set to SDR50\n"); return 0; type = 8; hs_type = UHS_SDR12_BUS_SPEED; -DPRINTF("[SD] Bus speed set to SDR12\n"); +DPRINTF("[SD] bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; default: @@ -916,7 +917,7 @@ DPRINTF("[SD] config tuning\n"); return _sdmmc_storage_check_status(storage); } -int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) +int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) { if (!_sd_storage_switch_get(storage, buf)) return 0; @@ -1064,8 +1065,9 @@ 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 is_version_1 = 0; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. + // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. sdmmc_storage_init_wait_sd(); memset(storage, 0, sizeof(sdmmc_storage_t)); @@ -1138,12 +1140,8 @@ DPRINTF("[SD] set blocklen to 512\n"); return 0; DPRINTF("[SD] cleared card detect\n"); - u8 *buf = (u8 *)malloc(512); if (!_sd_storage_get_scr(storage, buf)) - { - free(buf); return 0; - } //gfx_hexdump(0, storage->raw_scr, 8); DPRINTF("[SD] got scr\n"); @@ -1152,10 +1150,8 @@ DPRINTF("[SD] got scr\n"); if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) { if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) - { - free(buf); return 0; - } + sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); DPRINTF("[SD] switched to wide bus width\n"); } @@ -1166,20 +1162,15 @@ DPRINTF("[SD] SD does not support wide bus width\n"); if (storage->is_low_voltage) { - if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf)) - { - free(buf); + if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) return 0; - } DPRINTF("[SD] enabled UHS\n"); } else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) { - if (!_sd_storage_enable_highspeed_high_volt(storage, buf)) - { - free(buf); + if (!_sd_storage_enable_hs_high_volt(storage, buf)) return 0; - } + DPRINTF("[SD] enabled HS\n"); storage->csd.busspeed = 25; } @@ -1192,7 +1183,6 @@ DPRINTF("[SD] enabled HS\n"); DPRINTF("[SD] got sd status\n"); } - free(buf); return 1; } diff --git a/source/storage/sdmmc.h b/source/storage/sdmmc.h index fdc2bbb..c8b8f96 100644 --- a/source/storage/sdmmc.h +++ b/source/storage/sdmmc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 0c0c2ff..57d20f9 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -252,7 +252,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) u32 tmp; u16 divisor; - clock_sdmmc_get_params(&tmp, &divisor, type); + clock_sdmmc_get_card_clock_div(&tmp, &divisor, type); clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp); sdmmc->divisor = (tmp + divisor - 1) / divisor; @@ -722,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) sdmmc->regs->norintsts = norintsts & mask; return SDMMC_MASKINT_MASKED; } - + return SDMMC_MASKINT_NOERROR; } @@ -767,7 +767,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) if (!res) return 0; - + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_wait_prnsts_type1(sdmmc); @@ -830,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; if (req->is_auto_cmd12) trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); sdmmc->regs->trnmod = trnmode; return 1; @@ -855,7 +855,7 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) break; if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) { - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); return 1; // Transfer complete. } if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) @@ -901,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (res) { @@ -943,7 +943,7 @@ static int _sdmmc_config_sdmmc1() gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); - // Check if SD card is inserted. + // Check if SD card is inserted. if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) return 0; @@ -1015,7 +1015,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n u32 clock; u16 divisor; - clock_sdmmc_get_params(&clock, &divisor, type); + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); clock_sdmmc_enable(id, clock); sdmmc->clock_stopped = 0; @@ -1055,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc) if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); - // Disable SDMMC power. + // Disable SDMMC power. _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. @@ -1134,7 +1134,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); _sdmmc_get_clkcon(sdmmc); msleep(5); - + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; diff --git a/source/utils/btn.c b/source/utils/btn.c index f0a8ffc..678b19f 100644 --- a/source/utils/btn.c +++ b/source/utils/btn.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -61,16 +61,25 @@ u8 btn_wait() u8 btn_wait_timeout(u32 time_ms, u8 mask) { + u8 single_button = mask & BTN_SINGLE; + mask &= ~BTN_SINGLE; + u32 timeout = get_tmr_ms() + time_ms; - u8 res = btn_read() & mask; + u8 res = btn_read(); while (get_tmr_ms() < timeout) { - if (res == mask) - break; + if ((res & mask) == mask) + { + if (single_button && (res & ~mask)) // Undesired button detected. + res = btn_read(); + else + return (res & mask); + } else - res = btn_read() & mask; + res = btn_read(); }; - return res; + // Timed out. + return 0; } diff --git a/source/utils/btn.h b/source/utils/btn.h index ede13ac..d6cad0c 100644 --- a/source/utils/btn.h +++ b/source/utils/btn.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,6 +23,7 @@ #define BTN_POWER (1 << 0) #define BTN_VOL_DOWN (1 << 1) #define BTN_VOL_UP (1 << 2) +#define BTN_SINGLE (1 << 7) u8 btn_read(); u8 btn_wait(); diff --git a/source/utils/dirlist.c b/source/utils/dirlist.c index b4d0169..2bb8eaf 100644 --- a/source/utils/dirlist.c +++ b/source/utils/dirlist.c @@ -42,7 +42,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile break; if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) { - memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1); + strcpy(dir_entries + (k * 256), fno.fname); k++; if (k > (max_entries - 1)) break; @@ -56,7 +56,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) { - memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1); + strcpy(dir_entries + (k * 256), fno.fname); k++; if (k > (max_entries - 1)) break; @@ -81,9 +81,9 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) { - memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1); - memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1); - memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1); + strcpy(temp, &dir_entries[i * 256]); + strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); + strcpy(&dir_entries[j * 256], temp); } } } diff --git a/source/utils/types.h b/source/utils/types.h index ab6f35b..544e059 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -20,6 +20,7 @@ #define NULL ((void *)0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/source/utils/util.c b/source/utils/util.c index a217520..cae1981 100644 --- a/source/utils/util.c +++ b/source/utils/util.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (C) 2018 CTCaer +* Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,6 +17,7 @@ #include "util.h" #include "../gfx/di.h" +#include "../mem/minerva.h" #include "../power/max77620.h" #include "../rtc/max77620-rtc.h" #include "../soc/bpmp.h" @@ -26,6 +27,8 @@ #define USE_RTC_TIMER +extern volatile nyx_storage_t *nyx_str; + extern void sd_unmount(); u32 get_tmr_s() @@ -100,6 +103,8 @@ void reboot_normal() sd_unmount(); display_end(); + nyx_str->mtc_cfg.init_done = 0; + panic(0x21); // Bypass fuse programming in package1. } @@ -110,6 +115,8 @@ void reboot_rcm() sd_unmount(); display_end(); + nyx_str->mtc_cfg.init_done = 0; + PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm. PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; diff --git a/source/utils/util.h b/source/utils/util.h index 2eb0899..55f5f18 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,9 @@ #include "types.h" #include "../mem/minerva.h" +#define NYX_CFG_DUMP (1 << 7) +#define NYX_CFG_MINERVA (1 << 8) + #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) From f2e5413ef395816e0cea9e75d6e859bba3c8b299 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 9 Dec 2019 12:50:08 -0700 Subject: [PATCH 045/166] keys: Check emummc SD seed vector when appropriate --- source/keys/keys.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index c5a27d3..975e2b7 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -653,7 +653,14 @@ pkg2_done: TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]); } - if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { + char private_path[200] = "sd:/"; + if (emu_cfg.nintendo_path && (emu_cfg.enabled || !h_cfg.emummc_force_disable)) { + strcat(private_path, emu_cfg.nintendo_path); + } else { + strcat(private_path, "Nintendo"); + } + strcat(private_path, "/Contents/private"); + if (f_open(&fp, private_path, FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open SD seed vector. Skipping."); goto get_titlekeys; } From 12a076ca82678b149fdb2c96779b9eae02a2ea24 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 9 Dec 2019 12:50:38 -0700 Subject: [PATCH 046/166] heap: Integrate hekate rework --- common/common_heap.h | 7 +++++ source/mem/heap.c | 65 ++++++++++++++++++++++++++++++++++---------- source/mem/heap.h | 2 ++ 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/common/common_heap.h b/common/common_heap.h index 41a1973..f609add 100644 --- a/common/common_heap.h +++ b/common/common_heap.h @@ -25,6 +25,7 @@ typedef struct _hnode u32 size; struct _hnode *prev; struct _hnode *next; + u32 align[4]; // Align to arch cache line size. } hnode_t; typedef struct _heap @@ -32,3 +33,9 @@ typedef struct _heap u32 start; hnode_t *first; } heap_t; + +typedef struct +{ + u32 total; + u32 used; +} heap_monitor_t; diff --git a/source/mem/heap.c b/source/mem/heap.c index fd46c16..1e3493a 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -17,6 +17,7 @@ #include #include "heap.h" +#include "../gfx/gfx.h" #include "../../common/common_heap.h" static void _heap_create(heap_t *heap, u32 start) @@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start) heap->first = NULL; } -static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment) +// Node info is before node address. +static u32 _heap_alloc(heap_t *heap, u32 size) { hnode_t *node, *new; - int search = 1; - size = ALIGN(size, alignment); + // Align to cache line size. + size = ALIGN(size, sizeof(hnode_t)); if (!heap->first) { @@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment) } node = heap->first; - while (search) + while (true) { - if (!node->used && size + sizeof(hnode_t) < node->size) + if (!node->used && (size <= node->size)) { + u32 new_size = node->size - size; new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); - new->size = node->size - sizeof(hnode_t) - size; + // If there's aligned leftover space, create a new node. + if (new_size >= (sizeof(hnode_t) << 2)) + { + new->size = new_size - sizeof(hnode_t); + new->used = 0; + new->next = node->next; + new->next->prev = new; + new->prev = node; + node->next = new; + } + else + size += new_size; + node->size = size; node->used = 1; - new->used = 0; - new->next = node->next; - new->next->prev = new; - new->prev = node; - node->next = new; return (u32)node + sizeof(hnode_t); } if (node->next) node = node->next; else - search = 0; + break; } new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); @@ -108,12 +118,12 @@ void heap_init(u32 base) void *malloc(u32 size) { - return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t)); + return (void *)_heap_alloc(&_heap, size); } void *calloc(u32 num, u32 size) { - void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t)); + void *res = (void *)_heap_alloc(&_heap, num * size); memset(res, 0, num * size); return res; } @@ -123,3 +133,30 @@ void free(void *buf) if ((u32)buf >= _heap.start) _heap_free(&_heap, (u32)buf); } + +void heap_monitor(heap_monitor_t *mon, bool print_node_stats) +{ + u32 count = 0; + memset(mon, 0, sizeof(heap_monitor_t)); + + hnode_t *node = _heap.first; + while (true) + { + if (node->used) + mon->used += node->size + sizeof(hnode_t); + else + mon->total += node->size + sizeof(hnode_t); + + if (print_node_stats) + gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n", + count, node->used, (u32)node + sizeof(hnode_t), node->size); + + count++; + + if (node->next) + node = node->next; + else + break; + } + mon->total += mon->used; +} diff --git a/source/mem/heap.h b/source/mem/heap.h index 24cb64e..4ec3fb0 100644 --- a/source/mem/heap.h +++ b/source/mem/heap.h @@ -18,10 +18,12 @@ #define _HEAP_H_ #include "../utils/types.h" +#include "../../common/common_heap.h" void heap_init(u32 base); void *malloc(u32 size); void *calloc(u32 num, u32 size); void free(void *buf); +void heap_monitor(heap_monitor_t *mon, bool print_node_stats); #endif From d6794070c4fff021d51f904f570d096d76eb207b Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 9 Dec 2019 12:51:11 -0700 Subject: [PATCH 047/166] minerva: Fallback gracefully when old lib present --- source/mem/minerva.c | 14 ++++++++++---- source/mem/minerva.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/source/mem/minerva.c b/source/mem/minerva.c index 6683053..68aa66d 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -28,7 +28,7 @@ extern volatile nyx_storage_t *nyx_str; -void minerva_init() +u32 minerva_init() { u32 curr_ram_idx = 0; @@ -37,13 +37,17 @@ void minerva_init() // Set table to nyx storage. mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; - mtc_cfg->init_done = MTC_NEW_MAGIC; mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. + u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); - minerva_cfg = (void *)ep_addr; + + // Ensure that Minerva is new. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; if (!minerva_cfg) - return; + return 1; // Get current frequency for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) @@ -69,6 +73,8 @@ void minerva_init() // Switch to max. mtc_cfg->rate_to = 1600000; minerva_cfg(mtc_cfg, NULL); + + return 0; } void minerva_change_freq(minerva_freq_t freq) diff --git a/source/mem/minerva.h b/source/mem/minerva.h index f1edbaa..00228f4 100644 --- a/source/mem/minerva.h +++ b/source/mem/minerva.h @@ -58,7 +58,7 @@ typedef enum } minerva_freq_t; void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); -void minerva_init(); +u32 minerva_init(); void minerva_change_freq(minerva_freq_t freq); void minerva_periodic_training(); From 93c51bde6414baee5582411988e72e601739d347 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 9 Dec 2019 12:56:16 -0700 Subject: [PATCH 048/166] Bump version to v1.8.0 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cd2b95e..6313446 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 7 -LPVERSION_BUGFX := 1 +LPVERSION_MINOR := 8 +LPVERSION_BUGFX := 0 ################################################################################ From fa41ad507f2db11facf2100f5997093bd3eff5bb Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 16 Dec 2019 13:37:44 -0700 Subject: [PATCH 049/166] keys: Fix incorrect new console bis key derivation --- source/keys/keys.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 975e2b7..5188ef7 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -349,14 +349,16 @@ get_tsec: ; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { key_generation = fuse_read_odm(2) & 0x1F; + if (key_generation) + key_generation--; } } if (_key_exists(device_key)) { if (key_generation) { se_aes_key_set(8, new_device_key, 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); + se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[key_generation - KB_FIRMWARE_VERSION_400]); se_aes_key_set(8, master_key[0], 0x10); - se_aes_unwrap_key(8, 8, new_device_keygen_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); + se_aes_unwrap_key(8, 8, new_device_keygen_sources[key_generation - KB_FIRMWARE_VERSION_400]); se_aes_crypt_block_ecb(8, 0, temp_key, temp_key); } else memcpy(temp_key, device_key, 0x10); From a55e62d45ac4bac742eee46c890eb426db80846c Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 29 Dec 2019 14:32:37 -0700 Subject: [PATCH 050/166] Merge Hekate fixes to gfx, minerva --- source/gfx/gfx.c | 3 ++- source/mem/minerva.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 501b6f3..0d1c891 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -188,7 +188,7 @@ void gfx_putc(char c) for (u32 i = 0; i < 16; i+=2) { - u8 v = *cbuf++; + u8 v = *cbuf; for (u32 k = 0; k < 2; k++) { for (u32 j = 0; j < 8; j++) @@ -213,6 +213,7 @@ void gfx_putc(char c) fb += gfx_ctxt.stride - 16; v = *cbuf; } + cbuf++; } gfx_con.x += 16; if (gfx_con.x >= gfx_ctxt.width - 16) { diff --git a/source/mem/minerva.c b/source/mem/minerva.c index 68aa66d..d2c966e 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -32,6 +32,7 @@ u32 minerva_init() { u32 curr_ram_idx = 0; + minerva_cfg = NULL; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; // Set table to nyx storage. From e72e48628326d2593386a26972e20a276fd68853 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 30 Dec 2019 09:18:02 -0700 Subject: [PATCH 051/166] v1.8.1: Fixes for new console key derivation --- Makefile | 2 +- source/keys/keys.c | 67 +++++++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 6313446..70c4b02 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 0 +LPVERSION_BUGFX := 1 ################################################################################ diff --git a/source/keys/keys.c b/source/keys/keys.c index 5188ef7..99009b9 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -76,11 +76,19 @@ u32 start_time, end_time; #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) #define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) +static inline u32 _read_le_u32(const void *buffer, u32 offset) { + return (*(u8*)(buffer + offset + 0) ) | + (*(u8*)(buffer + offset + 1) << 0x08) | + (*(u8*)(buffer + offset + 2) << 0x10) | + (*(u8*)(buffer + offset + 3) << 0x18); +} + // key functions static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key); // nca functions static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); @@ -93,7 +101,7 @@ void dump_keys() { u8 temp_key[0x10], bis_key[4][0x20] = {0}, device_key[0x10] = {0}, - new_device_key[0x10] = {0}, + device_key_4x[0x10] = {0}, sd_seed[0x10] = {0}, // FS-related keys fs_keys[13][0x20] = {0}, @@ -102,6 +110,7 @@ void dump_keys() { // other sysmodule sources es_keys[3][0x10] = {0}, eticket_rsa_kek[0x10] = {0}, + eticket_rsa_kek_personalized[0x10] = {0}, ssl_keys[0x10] = {0}, ssl_rsa_kek[0x10] = {0}, // keyblob-derived families @@ -202,7 +211,7 @@ void dump_keys() { } } // write self to payload.bin to run again when sept finishes - u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; + u32 payload_size = _read_le_u32((u8 *)IPL_LOAD_ADDR, 0x84) - IPL_LOAD_ADDR; if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { EPRINTF("Unable to open /sept/payload.bin to write."); goto out_wait; @@ -314,7 +323,7 @@ get_tsec: ; se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, 0, new_device_key, per_console_key_source_4x); + se_aes_crypt_block_ecb(7, 0, device_key_4x, per_console_key_source_4x); } // verify keyblob is not corrupt @@ -355,11 +364,7 @@ get_tsec: ; } if (_key_exists(device_key)) { if (key_generation) { - se_aes_key_set(8, new_device_key, 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[key_generation - KB_FIRMWARE_VERSION_400]); - se_aes_key_set(8, master_key[0], 0x10); - se_aes_unwrap_key(8, 8, new_device_keygen_sources[key_generation - KB_FIRMWARE_VERSION_400]); - se_aes_crypt_block_ecb(8, 0, temp_key, temp_key); + _get_device_key(8, temp_key, key_generation, device_key_4x, master_key[0]); } else memcpy(temp_key, device_key, 0x10); se_aes_key_set(8, temp_key, 0x10); @@ -585,7 +590,7 @@ pkg2_done: } se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); // es doesn't contain es key sources on 1.0.0 - if (memcmp(pkg1_id->id, "2016", 4) && *(u32*)(dec_header + 0x210) == 0x33 && dec_header[0x205] == 0) { + if (memcmp(pkg1_id->id, "2016", 4) && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { u8 hash_order[3] = {0, 1, 2}; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { hash_order[0] = 1; @@ -609,7 +614,7 @@ pkg2_done: free(temp_file); temp_file = NULL; titles_found++; - } else if (*(u32*)(dec_header + 0x210) == 0x24 && dec_header[0x205] == 0) { + } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); @@ -720,13 +725,31 @@ get_titlekeys: se_aes_key_set(8, bis_key[2] + 0x00, 0x10); se_aes_key_set(9, bis_key[2] + 0x10, 0x10); - if (*(u32 *)buffer != 0x304C4143) { + if (_read_le_u32(buffer, 0) != 0x304C4143) { EPRINTF("CAL0 magic not found. Check BIS key 0."); free(buffer); goto dismount; } - se_aes_key_set(2, eticket_rsa_kek, 0x10); + u32 cal_version = _read_le_u32(buffer, 4); + u32 keypair_generation = _read_le_u32(buffer, 0x3AD0); + if (cal_version <= 8) + keypair_generation = 0; // settings zeroes this out below cal version 9 + + if (keypair_generation) { + keypair_generation--; + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + u8 temp_device_key[0x10] = {0}; + _get_device_key(7, temp_device_key, keypair_generation, device_key_4x, master_key[0]); + _generate_kek(7, es_keys[1], temp_device_key, temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek_personalized, es_keys[0]); + memcpy(temp_key, eticket_rsa_kek_personalized, 0x10); + } else { + memcpy(temp_key, eticket_rsa_kek, 0x10); + } + + se_aes_key_set(2, temp_key, 0x10); se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; @@ -916,7 +939,7 @@ key_output: ; EPRINTF("Unable to mount SD."); goto free_buffers; } - u32 text_buffer_size = _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1; + u32 text_buffer_size = _titlekey_count * 68 < 0x4000 ? 0x4000 : _titlekey_count * 68 + 1; text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); @@ -925,7 +948,9 @@ key_output: ; SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20); SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20); SAVE_KEY("device_key", device_key, 0x10); + SAVE_KEY("device_key_4x", device_key_4x, 0x10); SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); + SAVE_KEY("eticket_rsa_kek_personalized", eticket_rsa_kek_personalized, 0x10); SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10); SAVE_KEY("header_kek_source", fs_keys[0], 0x10); @@ -1054,11 +1079,17 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons se_aes_unwrap_key(ks, ks, key_seed); } -static inline u32 _read_le_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 0) ) | - (*(u8*)(buffer + offset + 1) << 0x08) | - (*(u8*)(buffer + offset + 2) << 0x10) | - (*(u8*)(buffer + offset + 3) << 0x18); +static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key) { + if (revision < KB_FIRMWARE_VERSION_400) + memcpy(out_device_key, device_key, 0x10); + + revision -= KB_FIRMWARE_VERSION_400; + u8 temp_key[0x10] = {0}; + se_aes_key_set(ks, device_key, 0x10); + se_aes_crypt_ecb(ks, 0, temp_key, 0x10, new_device_key_sources[revision], 0x10); + se_aes_key_set(ks, master_key, 0x10); + se_aes_unwrap_key(ks, ks, new_device_keygen_sources[revision]); + se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); } static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { From ef6676d3b9148147e2e64364ef8cfc219225a4c9 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 14 Apr 2020 15:07:58 -0600 Subject: [PATCH 052/166] pkg1: Key offsets for 10.0.0 --- source/hos/pkg1.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index e93ac0d..b1768f8 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -25,7 +25,7 @@ #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_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[] = { { "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 { "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 - { "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0 - { "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1 - { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 - { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0 - { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 - { "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.1.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_10x, 0x5563, 0x1d437} }, //7.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_10x, 0x5563, 0x1d437} }, //8.1.0 + { "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_10x, 0x6495, 0x1d807} }, //9.1.0 + { "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0 { NULL } //End. }; From a7d20c58147b46dc6a00d907ff459446b15a23cf Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 14 Apr 2020 15:10:51 -0600 Subject: [PATCH 053/166] pkg2: Improve Ini1 kernel offset code per hekate --- source/hos/pkg2.c | 28 ++++++++++++++++++++++++---- source/hos/pkg2.h | 4 ++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index e745cbc..6b0baa0 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it @@ -41,12 +41,32 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) void pkg2_get_newkern_info(u8 *kern_data) { - u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); - pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. + u32 pkg2_newkern_ini1_off = 0; + 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_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); -} + } void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index 0cb9962..2ea8796 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -26,7 +26,7 @@ #define PKG2_SEC_KERNEL 0 #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_start; From 25ff127404b12bdffb5588d426bb4f538db77fbe Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Apr 2020 16:18:58 -0600 Subject: [PATCH 054/166] Merge hekate 5.1.4 changes --- source/config/config.c | 104 ++++++++++-------------------------- source/config/config.h | 8 +-- source/config/ini.c | 19 ++++--- source/hos/pkg2.c | 7 ++- source/hos/pkg2.h | 2 +- source/keys/keys.c | 5 +- source/main.c | 27 +++++++--- source/mem/heap.c | 46 ++++++++++------ source/mem/heap.h | 1 + source/mem/minerva.c | 5 +- source/mem/sdram.c | 3 +- source/power/max17050.h | 9 +++- source/power/max7762x.c | 5 +- source/power/max7762x.h | 4 +- source/rtc/max77620-rtc.c | 94 +++++++++++++++++++++++++++++++- source/rtc/max77620-rtc.h | 2 + source/soc/hw_init.c | 31 +++++++---- source/soc/i2c.c | 8 ++- source/soc/i2c.h | 2 + source/storage/nx_emmc.c | 2 +- source/utils/aarch64_util.h | 12 +++-- source/utils/btn.c | 15 +++++- source/utils/btn.h | 1 + source/utils/list.h | 6 ++- source/utils/util.h | 11 +++- 25 files changed, 277 insertions(+), 152 deletions(-) diff --git a/source/config/config.c b/source/config/config.c index 38e5bcf..23b516f 100644 --- a/source/config/config.c +++ b/source/config/config.c @@ -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 * under the terms and conditions of the GNU General Public License, @@ -37,12 +37,12 @@ void set_default_configuration() h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; - h_cfg.verification = 1; h_cfg.se_keygen_done = 0; h_cfg.sbar_time_keeping = 0; h_cfg.backlight = 100; h_cfg.autohosoff = 0; h_cfg.autonogc = 1; + h_cfg.updater2p = 0; h_cfg.brand = NULL; h_cfg.tagline = NULL; h_cfg.errors = 0; @@ -50,7 +50,7 @@ void set_default_configuration() h_cfg.rcm_patched = true; h_cfg.emummc_force_disable = false; - sd_power_cycle_time_start = 0xFFFFFFF; + sd_power_cycle_time_start = 0; } int create_config_entry() @@ -96,9 +96,6 @@ int create_config_entry() f_puts("\nbootwait=", &fp); itoa(h_cfg.bootwait, lbuf, 10); f_puts(lbuf, &fp); - f_puts("\nverification=", &fp); - itoa(h_cfg.verification, lbuf, 10); - f_puts(lbuf, &fp); f_puts("\nbacklight=", &fp); itoa(h_cfg.backlight, lbuf, 10); f_puts(lbuf, &fp); @@ -108,6 +105,9 @@ int create_config_entry() f_puts("\nautonogc=", &fp); itoa(h_cfg.autonogc, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nupdater2p=", &fp); + itoa(h_cfg.updater2p, lbuf, 10); + f_puts(lbuf, &fp); if (h_cfg.brand) { f_puts("\nbrand=", &fp); @@ -281,10 +281,11 @@ void config_autoboot() LIST_INIT(ini_sections); u8 max_entries = 30; + u32 boot_text_size = 512; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); 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++) boot_values[j] = j; @@ -330,12 +331,12 @@ void config_autoboot() else { if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) - boot_text[(i - 4) * 512] = ' '; + boot_text[(i - 4) * boot_text_size] = ' '; else - boot_text[(i - 4) * 512] = '*'; - strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 4) * 512]; + boot_text[(i - 4) * boot_text_size] = '*'; + strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 4) * boot_text_size]; } ments[i].type = ini_sec->type; ments[i].data = &boot_values[i - 4]; @@ -391,10 +392,11 @@ void config_bootdelay() gfx_con_setpos(0, 0); u32 delay_entries = 6; + u32 delay_text_size = 32; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); 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++) delay_values[j] = j; @@ -415,14 +417,14 @@ void config_bootdelay() for (i = 1; i < delay_entries; i++) { if (h_cfg.bootwait != i) - delay_text[i * 32] = ' '; + delay_text[i * delay_text_size] = ' '; else - delay_text[i * 32] = '*'; - delay_text[i * 32 + 1] = i + '0'; - strcpy(delay_text + i * 32 + 2, " seconds"); + delay_text[i * delay_text_size] = '*'; + delay_text[i * delay_text_size + 1] = i + '0'; + strcpy(delay_text + i * delay_text_size + 2, " seconds"); 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]; } @@ -445,69 +447,17 @@ void config_bootdelay() 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() { gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); + u32 bri_text_size = 8; u32 bri_entries = 11; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); 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++) bri_values[j] = j * 10; @@ -521,20 +471,20 @@ void config_backlight() for (i = 1; i < bri_entries; i++) { if ((h_cfg.backlight / 20) != i) - bri_text[i * 32] = ' '; + bri_text[i * bri_text_size] = ' '; else - bri_text[i * 32] = '*'; + bri_text[i * bri_text_size] = '*'; if (i < 10) { - bri_text[i * 32 + 1] = i + '0'; - strcpy(bri_text + i * 32 + 2, "0%"); + bri_text[i * bri_text_size + 1] = i + '0'; + strcpy(bri_text + i * bri_text_size + 2, "0%"); } 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].caption = bri_text + i * 32; + ments[i + 1].caption = bri_text + (i * bri_text_size); ments[i + 1].data = &bri_values[i]; } diff --git a/source/config/config.h b/source/config/config.h index 8cd34e1..0410a7e 100644 --- a/source/config/config.h +++ b/source/config/config.h @@ -25,10 +25,10 @@ typedef struct _hekate_config u32 autoboot; u32 autoboot_list; u32 bootwait; - u32 verification; u32 backlight; u32 autohosoff; u32 autonogc; + u32 updater2p; char *brand; char *tagline; // Global temporary config. @@ -40,16 +40,10 @@ typedef struct _hekate_config u32 errors; } hekate_config; -typedef enum -{ - ERR_LIBSYS_LP0 = (1 << 0), -} hsysmodule_t; - void set_default_configuration(); int create_config_entry(); void config_autoboot(); void config_bootdelay(); -void config_verification(); void config_backlight(); void config_auto_hos_poweroff(); void config_nogc(); diff --git a/source/config/ini.c b/source/config/ini.c index e807aec..85a19b1 100644 --- a/source/config/ini.c +++ b/source/config/ini.c @@ -1,6 +1,6 @@ /* * 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 * 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 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; @@ -123,8 +124,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) f_gets(lbuf, 512, &fp); lblen = strlen(lbuf); - // Remove trailing newline. - if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. + if (lblen && lbuf[lblen - 1] == '\n') lbuf[lblen - 1] = 0; if (lblen > 2 && lbuf[0] == '[') // Create new section. @@ -134,24 +135,22 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); 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, '}'); csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); 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); } - else if (lblen < 2) + else if (lblen < 2) // Create empty line. { 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, '='); diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index 6b0baa0..bc77d1e 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -68,7 +68,7 @@ void pkg2_get_newkern_info(u8 *kern_data) 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; // Check for new pkg2 type. @@ -76,6 +76,9 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { pkg2_get_newkern_info(pkg2->data); + if (!pkg2_newkern_ini1_start) + return false; + ptr = pkg2->data + pkg2_newkern_ini1_start; *new_pkg2 = true; } @@ -95,6 +98,8 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) ptr += 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) diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index 2ea8796..ba6a8a0 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -87,7 +87,7 @@ typedef struct _pkg2_kip1_info_t link_t link; } pkg2_kip1_info_t; -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, 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); pkg2_hdr_t *pkg2_decrypt(void *data); diff --git a/source/keys/keys.c b/source/keys/keys.c index 99009b9..6d56304 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -441,7 +441,10 @@ get_tsec: ; LIST_INIT(kip1_info); bool new_pkg2; - pkg2_parse_kips(&kip1_info, pkg2_hdr, &new_pkg2); + if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &new_pkg2)) { + EPRINTF("Unable to locate INI1."); + goto pkg2_done; + } LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) { if(ki_tmp->kip1->tid == 0x0100000000000000ULL) { ki = malloc(sizeof(pkg2_kip1_info_t)); diff --git a/source/main.c b/source/main.c index 4d3ee27..bb39156 100644 --- a/source/main.c +++ b/source/main.c @@ -135,12 +135,14 @@ int sd_save_to_file(void *buf, u32 size, const char *filename) #define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_STACK 0x40007000 #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 COREBOOT_ADDR (0xD0000000 - 0x100000) +#define COREBOOT_END_ADDR 0xD0000000 #define CBFS_DRAM_EN_ADDR 0x4003e000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" +static void *coreboot_addr; + void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); @@ -154,7 +156,7 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) 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; } } @@ -184,7 +186,10 @@ int launch_payload(char *path) if (size < 0x30000) buf = (void *)RCM_PAYLOAD_ADDR; else - buf = (void *)COREBOOT_ADDR; + { + coreboot_addr = (void *)(COREBOOT_END_ADDR - size); + buf = coreboot_addr; + } if (f_read(&fp, buf, size, NULL)) { @@ -402,26 +407,35 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) { extern void pivot_stack(u32 stack_top); -// todo: chainload to reboot payload or payloads folder option? - void ipl_main() { + // Do initial HW configuration. This is compatible with consecutive reruns without a reset. config_hw(); + + // Pivot the stack so we have enough space. pivot_stack(IPL_STACK_TOP); + + // Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. heap_init(IPL_HEAP_START); + // Set bootloader's default configuration. set_default_configuration(); sd_mount(); + minerva_init(); minerva_change_freq(FREQ_1600); display_init(); + u32 *fb = display_init_framebuffer(); gfx_init_ctxt(fb, 720, 1280, 720); + gfx_con_init(); + display_backlight_pwm_init(); + // Overclock BPMP. bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); h_cfg.emummc_force_disable = emummc_load_cfg(); @@ -445,6 +459,7 @@ void ipl_main() while (true) tui_do_menu(&menu_top); + // Halt BPMP if we managed to get out of execution. while (true) bpmp_halt(); } diff --git a/source/mem/heap.c b/source/mem/heap.c index 1e3493a..4ed7230 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018 M4xw * * 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. static u32 _heap_alloc(heap_t *heap, u32 size) { - hnode_t *node, *new; + hnode_t *node, *new_node; // Align to cache line size. size = ALIGN(size, sizeof(hnode_t)); @@ -49,22 +50,29 @@ static u32 _heap_alloc(heap_t *heap, u32 size) node = heap->first; while (true) { + // Check if there's available unused node. if (!node->used && (size <= node->size)) { + // Size and offset of the new unused node. 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)) { - new->size = new_size - sizeof(hnode_t); - new->used = 0; - new->next = node->next; - new->next->prev = new; - new->prev = node; - node->next = new; + new_node->size = new_size - sizeof(hnode_t); + new_node->used = 0; + new_node->next = node->next; + + // Check that we are not on first node. + 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; node->size = size; @@ -72,20 +80,23 @@ static u32 _heap_alloc(heap_t *heap, u32 size) return (u32)node + sizeof(hnode_t); } + + // No unused node found, try the next one. if (node->next) node = node->next; else break; } - new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); - new->used = 1; - new->size = size; - new->prev = node; - new->next = NULL; - node->next = new; + // No unused node found, create a new one. + new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); + new_node->used = 1; + new_node->size = size; + new_node->prev = node; + 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) @@ -101,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr) { node->prev->size += node->size + sizeof(hnode_t); node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; } diff --git a/source/mem/heap.h b/source/mem/heap.h index 4ec3fb0..e029597 100644 --- a/source/mem/heap.h +++ b/source/mem/heap.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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, diff --git a/source/mem/minerva.c b/source/mem/minerva.c index d2c966e..84efee0 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -34,18 +34,21 @@ u32 minerva_init() minerva_cfg = NULL; 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. mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. - + u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); // Ensure that Minerva is new. if (mtc_cfg->init_done == MTC_INIT_MAGIC) minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; if (!minerva_cfg) return 1; diff --git a/source/mem/sdram.c b/source/mem/sdram.c index a9a26d3..3bc283d 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * 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 * under the terms and conditions of the GNU General Public License, @@ -696,7 +696,6 @@ sdram_params_t *sdram_get_params_patched() void sdram_init() { - //TODO: sdram_id should be in [0,4]. const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); // Set DRAM voltage. diff --git a/source/power/max17050.h b/source/power/max17050.h index e4c8acf..30a7ca0 100644 --- a/source/power/max17050.h +++ b/source/power/max17050.h @@ -4,7 +4,7 @@ * * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * 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 @@ -96,14 +96,17 @@ enum MAX17050_reg { MAX17050_K_empty0 = 0x3B, MAX17050_TaskPeriod = 0x3C, MAX17050_FSTAT = 0x3D, - + MAX17050_TIMER = 0x3E, MAX17050_SHDNTIMER = 0x3F, + MAX17050_QRTbl30 = 0x42, + MAX17050_dQacc = 0x45, MAX17050_dPacc = 0x46, MAX17050_VFSOC0 = 0x48, + Max17050_QH0 = 0x4C, MAX17050_QH = 0x4D, MAX17050_QL = 0x4E, @@ -111,6 +114,8 @@ enum MAX17050_reg { MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. MAX17050_VFSOC0Enable = 0x60, + MAX17050_MODELEnable1 = 0x62, + MAX17050_MODELEnable2 = 0x63, MAX17050_MODELChrTbl = 0x80, diff --git a/source/power/max7762x.c b/source/power/max7762x.c index 0e7a6b5..ce07cbe 100644 --- a/source/power/max7762x.c +++ b/source/power/max7762x.c @@ -137,6 +137,7 @@ int max77620_regulator_enable(u32 id, int enable) return 1; } +// LDO only. int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) { if (id > REGULATOR_MAX) @@ -168,9 +169,9 @@ void max77620_config_default() _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_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/source/power/max7762x.h b/source/power/max7762x.h index 3a0afe3..8a11a9f 100644 --- a/source/power/max7762x.h +++ b/source/power/max7762x.h @@ -33,7 +33,7 @@ * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | @@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); -void max77620_low_battery_monitor_config(); +void max77620_low_battery_monitor_config(bool enable); #endif diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index e214363..98243d2 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -1,7 +1,8 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm() // Update RTC clock from RTC regs. 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; +} diff --git a/source/rtc/max77620-rtc.h b/source/rtc/max77620-rtc.h index 981ccfe..99199d2 100644 --- a/source/rtc/max77620-rtc.h +++ b/source/rtc/max77620-rtc.h @@ -71,5 +71,7 @@ typedef struct _rtc_time_t { void max77620_rtc_get_time(rtc_time_t *time); 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_ */ diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 9f0e900..a7703a2 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -39,6 +39,7 @@ extern sdmmc_t sd_sdmmc; extern boot_cfg_t b_cfg; +extern volatile nyx_storage_t *nyx_str; /* * CLK_OSC - 38.4 MHz crystal. @@ -78,8 +79,8 @@ void _config_gpios() PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; // Set Joy-Con IsAttached direction. - PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE; - PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE; + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. #if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B @@ -109,7 +110,7 @@ void _config_gpios() gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); // Configure HOME as inputs. - // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE; + // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); } @@ -160,7 +161,7 @@ void _mbist_workaround() // Enable specific clocks and disable all others. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. - //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON. + //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_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_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. @@ -184,6 +185,9 @@ void _mbist_workaround() void _config_se_brom() { + // Enable fuse clock. + clock_enable_fuse(true); + // Skip SBK/SSK if sept was run. if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) { @@ -217,10 +221,19 @@ void _config_se_brom() 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_ONOFFCNFG1, (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, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, @@ -236,10 +249,10 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ - // Set vdd_core voltage to 1.125V + // Set vdd_core voltage to 1.125V. 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_GPIO6, 2); @@ -256,9 +269,6 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - // Enable low battery shutdown monitor for < 2800mV. - max77620_low_battery_monitor_config(); } void config_hw() @@ -312,6 +322,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) bpmp_mmu_disable(); bpmp_clk_rate_set(BPMP_CLK_NORMAL); minerva_change_freq(FREQ_204); + nyx_str->mtc_cfg.init_done = 0; // 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. diff --git a/source/soc/i2c.c b/source/soc/i2c.c index d06d64a..94239b5 100644 --- a/source/soc/i2c.c +++ b/source/soc/i2c.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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, @@ -19,7 +20,7 @@ #include "i2c.h" #include "../utils/util.h" -static u32 i2c_addrs[] = { +static const u32 i2c_addrs[] = { 0x7000C000, 0x7000C400, 0x7000C500, 0x7000C700, 0x7000D000, 0x7000D100 }; @@ -121,6 +122,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); } +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 res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); diff --git a/source/soc/i2c.h b/source/soc/i2c.h index e2b2af5..4f04bac 100644 --- a/source/soc/i2c.h +++ b/source/soc/i2c.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 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, @@ -39,6 +40,7 @@ void i2c_init(u32 idx); 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_send_byte(u32 idx, u32 x, u32 y, u8 b); u8 i2c_recv_byte(u32 idx, u32 x, u32 y); diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index c35177e..2cae846 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -31,7 +31,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) 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 *)malloc(sizeof(emmc_part_t)); + emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1); part->lba_start = ent->lba_start; part->lba_end = ent->lba_end; part->attrs = ent->attrs; diff --git a/source/utils/aarch64_util.h b/source/utils/aarch64_util.h index 3fa0188..a5002c0 100644 --- a/source/utils/aarch64_util.h +++ b/source/utils/aarch64_util.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -25,11 +26,12 @@ #define _PAGEOFF(x) ((x) & 0xFFFFF000) -#define _ADRP(r, o) 0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F) -#define _BL(a, o) 0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF) -#define _B(a, o) 0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF) -#define _MOVKX(r, i, s) 0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) -#define _MOVZX(r, i, s) 0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) +#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F)) +#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) #define _NOP() 0xD503201F #endif diff --git a/source/utils/btn.c b/source/utils/btn.c index 678b19f..5a1d024 100644 --- a/source/utils/btn.c +++ b/source/utils/btn.c @@ -34,6 +34,16 @@ u8 btn_read() return res; } +u8 btn_read_vol() +{ + u8 res = 0; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) + res |= BTN_VOL_DOWN; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) + res |= BTN_VOL_UP; + return res; +} + u8 btn_wait() { u8 res = 0, btn = btn_read(); @@ -81,5 +91,8 @@ u8 btn_wait_timeout(u32 time_ms, u8 mask) }; // Timed out. - return 0; + if (!single_button || !time_ms) + return (res & mask); + else + return 0; // Return no button press if single button requested. } diff --git a/source/utils/btn.h b/source/utils/btn.h index d6cad0c..4f6b4d2 100644 --- a/source/utils/btn.h +++ b/source/utils/btn.h @@ -26,6 +26,7 @@ #define BTN_SINGLE (1 << 7) u8 btn_read(); +u8 btn_read_vol(); u8 btn_wait(); u8 btn_wait_timeout(u32 time_ms, u8 mask); diff --git a/source/utils/list.h b/source/utils/list.h index 7d43e36..80e4498 100644 --- a/source/utils/list.h +++ b/source/utils/list.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 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, @@ -33,9 +34,10 @@ #define LIST_FOREACH_SAFE(iter, list) \ for(link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next) -/*! Iterate over all list members. */ +/*! Iterate over all list members and make sure that the list has at least one entry. */ #define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ - for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + if ((list)->next != (list)) \ + for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) typedef struct _link_t { diff --git a/source/utils/util.h b/source/utils/util.h index 55f5f18..9ee1a74 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -33,15 +33,22 @@ typedef struct _cfg_op_t u32 val; } cfg_op_t; +typedef struct _nyx_info_t +{ + u32 rsvd; + u32 errors; +} nyx_info_t; + typedef struct _nyx_storage_t { u32 version; u32 cfg; u8 irama[0x8000]; u8 hekate[0x30000]; - u8 rsvd[0x800000]; + u8 rsvd[0x800000 - sizeof(nyx_info_t)]; + nyx_info_t info; mtc_config_t mtc_cfg; - emc_table_t mtc_table; + emc_table_t mtc_table[10]; } nyx_storage_t; u32 get_tmr_us(); From 8a742a45d4963aa9d0332f5a9e3dfbe4ace5a262 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Apr 2020 16:22:23 -0600 Subject: [PATCH 055/166] save: Fix remap init, add graceful fail paths --- source/keys/keys.c | 18 ++++++++----- source/keys/save.c | 67 +++++++++++++++++++++++++--------------------- source/keys/save.h | 6 ++--- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 6d56304..216297c 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -780,7 +780,7 @@ get_titlekeys: save_ctx = calloc(1, sizeof(save_ctx_t)); u8 M[0x100]; if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ES save 1. Skipping."); + EPRINTF("Unable to open e1 save. Skipping."); free(buffer); goto dismount; } @@ -791,7 +791,9 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - save_process(save_ctx); + if (!save_process(save_ctx)) { + EPRINTF("Failed to process e1 save."); + } char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; char ticket_list_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket_list.bin"; @@ -813,7 +815,7 @@ get_titlekeys: } } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { - EPRINTF("Unable to locate ticket.bin in e1."); + EPRINTF("Unable to locate ticket.bin in e1 save."); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -852,7 +854,7 @@ get_titlekeys: u32 common_titlekey_count = _titlekey_count; if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ES save 2. Skipping."); + EPRINTF("Unable to open e2 save. Skipping."); free(buffer); goto dismount; } @@ -860,10 +862,12 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - save_process(save_ctx); + if (!save_process(save_ctx)) { + EPRINTF("Failed to process e1 save."); + } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { - EPRINTF("Unable to locate ticket_list.bin in e2."); + EPRINTF("Unable to locate ticket_list.bin in e2 save."); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -881,7 +885,7 @@ get_titlekeys: } } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { - EPRINTF("Unable to locate ticket.bin in e2."); + EPRINTF("Unable to locate ticket.bin in e2 save."); goto dismount; } diff --git a/source/keys/save.c b/source/keys/save.c index bcac3b4..7b0695a 100644 --- a/source/keys/save.c +++ b/source/keys/save.c @@ -70,27 +70,27 @@ uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint6 } remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) { - remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count); + remap_segment_ctx_t *segments = calloc(1, sizeof(remap_segment_ctx_t) * header->map_segment_count); unsigned int entry_idx = 0; for (unsigned int i = 0; i < header->map_segment_count; i++) { remap_segment_ctx_t *seg = &segments[i]; - seg->entries = malloc(sizeof(remap_entry_ctx_t)); - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); + seg->entry_count = 0; + seg->entries = malloc(sizeof(remap_entry_ctx_t *)); + seg->entries[seg->entry_count++] = &map_entries[entry_idx]; seg->offset = map_entries[entry_idx].virtual_offset; - map_entries[entry_idx].segment = seg; - seg->entry_count = 1; - entry_idx++; + map_entries[entry_idx++].segment = seg; while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { map_entries[entry_idx].segment = seg; map_entries[entry_idx - 1].next = &map_entries[entry_idx]; - seg->entries = malloc(sizeof(remap_entry_ctx_t)); - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); - seg->entry_count++; - entry_idx++; + remap_entry_ctx_t **ptr = calloc(1, sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1)); + memcpy(ptr, seg->entries, sizeof(remap_entry_ctx_t *) * (seg->entry_count)); + free(seg->entries); + seg->entries = ptr; + seg->entries[seg->entry_count++] = &map_entries[entry_idx++]; } - seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset; + seg->length = seg->entries[seg->entry_count - 1]->virtual_offset_end - seg->entries[0]->virtual_offset; } return segments; } @@ -99,8 +99,8 @@ remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t o uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits)); if (segment_idx < ctx->header->map_segment_count) { for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) - if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset) - return &ctx->segments[segment_idx].entries[i]; + if (ctx->segments[segment_idx].entries[i]->virtual_offset_end > offset) + return ctx->segments[segment_idx].entries[i]; } return NULL; } @@ -179,7 +179,7 @@ void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *c uint32_t length; }; - static struct salt_source_t salt_sources[6] = { + static const struct salt_source_t salt_sources[6] = { {"HierarchicalIntegrityVerificationStorage::Master", 48}, {"HierarchicalIntegrityVerificationStorage::L1", 44}, {"HierarchicalIntegrityVerificationStorage::L2", 44}, @@ -238,12 +238,14 @@ size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) { if (count > ctx->sector_size) { EPRINTF("IVFC read exceeds sector size!\n"); + return; } uint64_t block_index = offset / ctx->sector_size; if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count); + return; } uint8_t hash_buffer[0x20] = {0}; @@ -270,7 +272,7 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf uint8_t hash[0x20] = {0}; uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20); memcpy(data_buffer, ctx->salt, 0x20); - memcpy(data_buffer + 0x20, buffer, count); + memcpy(data_buffer + 0x20, buffer, ctx->sector_size); se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20); hash[0x1F] |= 0x80; @@ -284,6 +286,7 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count); + return; } } @@ -295,6 +298,7 @@ uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ct if ((entries[0].next & 0x80000000) == 0) { if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) { EPRINTF("Invalid range entry in allocation table!\n"); + return 0; } } else { length = entries[1].next - entry_index + 1; @@ -354,6 +358,7 @@ void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, if (ctx->prev_block != 0xFFFFFFFF) { EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block); + return; } } @@ -464,6 +469,8 @@ uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_ while (index) { if (index > capacity) { EPRINTFARGS("Save entry index %d out of range!", index); + *prev_index = 0xFFFFFFFF; + return 0xFFFFFFFF; } save_fs_list_read_entry(ctx, index, &entry); if (entry.parent == key->parent && !strcmp(entry.name, key->name)) { @@ -619,26 +626,25 @@ validity_t save_filesystem_verify(save_ctx_t *ctx) { return journal_validity; } -void save_process(save_ctx_t *ctx) { +bool save_process(save_ctx_t *ctx) { /* Try to parse Header A. */ f_lseek(ctx->file, 0); if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { EPRINTF("Failed to read save header!\n"); + return false; } - save_process_header(ctx); - - if (ctx->header_hash_validity == VALIDITY_INVALID) { + if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { /* Try to parse Header B. */ f_lseek(ctx->file, 0x4000); if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { EPRINTF("Failed to read save header!\n"); + return false; } - save_process_header(ctx); - - if (ctx->header_hash_validity == VALIDITY_INVALID) { + if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { EPRINTF("Error: Save header is invalid!\n"); + return false; } } @@ -759,14 +765,18 @@ void save_process(save_ctx_t *ctx) { /* Initialize core save filesystem. */ ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage; save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header); + + return true; } -void save_process_header(save_ctx_t *ctx) { +bool save_process_header(save_ctx_t *ctx) { if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS || ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL || ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || - ctx->header.meta_remap_header.magic != MAGIC_RMAP) { + ctx->header.meta_remap_header.magic != MAGIC_RMAP) + { EPRINTF("Error: Save header is corrupt!\n"); + return false; } ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; @@ -781,19 +791,16 @@ void save_process_header(save_ctx_t *ctx) { if (ctx->header.layout.version >= 0x50000) { ctx->header.fat_ivfc_header.num_levels = 4; } + return true; } void save_free_contexts(save_ctx_t *ctx) { for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { - for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) { - free(&ctx->data_remap_storage.segments[i].entries[j]); - } + free(ctx->data_remap_storage.segments[i].entries); } free(ctx->data_remap_storage.segments); for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { - for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) { - free(&ctx->meta_remap_storage.segments[i].entries[j]); - } + free(ctx->meta_remap_storage.segments[i].entries); } free(ctx->meta_remap_storage.segments); free(ctx->data_remap_storage.map_entries); diff --git a/source/keys/save.h b/source/keys/save.h index ea44906..f7006ca 100644 --- a/source/keys/save.h +++ b/source/keys/save.h @@ -157,7 +157,7 @@ struct remap_entry_ctx_t { struct remap_segment_ctx_t{ uint64_t offset; uint64_t length; - remap_entry_ctx_t *entries; + remap_entry_ctx_t **entries; uint64_t entry_count; }; @@ -472,8 +472,8 @@ static inline uint32_t save_allocation_table_get_free_list_block_index(allocatio return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); } -void save_process(save_ctx_t *ctx); -void save_process_header(save_ctx_t *ctx); +bool save_process(save_ctx_t *ctx); +bool save_process_header(save_ctx_t *ctx); void save_save(save_ctx_t *ctx); void save_print(save_ctx_t *ctx); From 7c6a3b1d3eefdd6e2155c95805ef8e9a070e9c89 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Apr 2020 17:04:07 -0600 Subject: [PATCH 056/166] Update readme and copyrights --- README.md | 6 +++++- source/gfx/gfx.c | 2 +- source/keys/key_sources.inl | 2 +- source/keys/keys.h | 2 +- source/libs/fatfs/diskio.c | 2 +- source/rtc/max77620-rtc.c | 2 +- source/sec/se.c | 2 +- source/utils/sprintf.c | 2 +- source/utils/sprintf.h | 2 +- 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index bd13c65..8365383 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,8 @@ Install [devkitARM](https://devkitpro.org/) and run `make`. Massive Thanks to CTCaer! = -This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor. \ No newline at end of file +This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor. + +License += +This project is under the GPLv2 license. The Save processing module is adapted from [hactool](https://github.com/SciresM/hactool) code under ISC. \ No newline at end of file diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 0d1c891..6adb7be 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018-2019 CTCaer - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 5b0f6b7..dca7303 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/keys/keys.h b/source/keys/keys.h index 9be86dd..a0f7afd 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 0dea450..592d8f0 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index 98243d2..d2a780a 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -2,7 +2,7 @@ * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/sec/se.c b/source/sec/se.c index 7416d38..6eb4700 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 CTCaer * 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 * under the terms and conditions of the GNU General Public License, diff --git a/source/utils/sprintf.c b/source/utils/sprintf.c index a310251..c27043c 100644 --- a/source/utils/sprintf.c +++ b/source/utils/sprintf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/utils/sprintf.h b/source/utils/sprintf.h index 18c36b5..6094044 100644 --- a/source/utils/sprintf.h +++ b/source/utils/sprintf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, From b536a98b8dd50f5d4ad0b8257a6900e8bbe780c4 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Apr 2020 17:05:20 -0600 Subject: [PATCH 057/166] keys: Fix freeze when es saves not present --- source/keys/keys.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 216297c..5cef76f 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -556,6 +556,7 @@ pkg2_done: FILINFO fno; FIL fp; save_ctx_t *save_ctx = NULL; + bool save_process_success = false; // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient u8 *dec_header = (u8*)malloc(0x600); @@ -791,8 +792,10 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - if (!save_process(save_ctx)) { + save_process_success = save_process(save_ctx); + if (!save_process_success) { EPRINTF("Failed to process e1 save."); + goto dismount; } char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; @@ -843,6 +846,7 @@ get_titlekeys: tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); f_close(&fp); save_free_contexts(save_ctx); + save_process_success = false; memset(save_ctx, 0, sizeof(save_ctx_t)); memset(&fat_storage, 0, sizeof(allocation_table_storage_ctx_t)); @@ -862,8 +866,10 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - if (!save_process(save_ctx)) { - EPRINTF("Failed to process e1 save."); + save_process_success = save_process(save_ctx); + if (!save_process_success) { + EPRINTF("Failed to process e2 save."); + goto dismount; } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { @@ -932,8 +938,10 @@ get_titlekeys: gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); dismount:; - if (save_ctx) { + if (save_process_success) { save_free_contexts(save_ctx); + } + if (save_ctx) { free(save_ctx); } f_mount(NULL, "emmc:", 1); From a120e97e08e03aea290a36524b6b52a3532df30b Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Apr 2020 17:06:07 -0600 Subject: [PATCH 058/166] Bump version to v1.8.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 70c4b02..d810cec 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 1 +LPVERSION_BUGFX := 2 ################################################################################ From b147f34c532a4a943c9b1e120dd59319de752aaf Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 8 May 2020 15:22:47 -0600 Subject: [PATCH 059/166] se: Improve general xts function --- source/sec/se.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/source/sec/se.c b/source/sec/se.c index 6eb4700..c5e19b3 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -19,6 +19,7 @@ #include +#include "../../common/memory_map.h" #include "../sec/se.h" #include "../mem/heap.h" #include "../soc/bpmp.h" @@ -94,7 +95,7 @@ static int _se_wait() static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) { - se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0; + se_ll_t *ll_dst = (se_ll_t *)(NYX_STORAGE_ADDR - 0x20), *ll_src = (se_ll_t *)(NYX_STORAGE_ADDR - 0x10); if (dst) { @@ -324,8 +325,10 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo { int res = 0; u8 *tweak = (u8 *)malloc(0x10); - u8 *pdst = (u8 *)dst; - u8 *psrc = (u8 *)src; + u8 *temptweak = (u8 *)malloc(0x10); + u32 *pdst = (u32 *)dst; + u32 *psrc = (u32 *)src; + u32 *ptweak = (u32 *)tweak; //Generate tweak. for (int i = 0xF; i >= 0; i--) @@ -336,23 +339,34 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) goto out; + memcpy(temptweak, tweak, 0x10); + //We are assuming a 0x10-aligned sector size in this implementation. for (u32 i = 0; i < secsize / 0x10; i++) { - for (u32 j = 0; j < 0x10; j++) - pdst[j] = psrc[j] ^ tweak[j]; - if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst)) - goto out; - for (u32 j = 0; j < 0x10; j++) - pdst[j] = pdst[j] ^ tweak[j]; + for (u32 j = 0; j < 4; j++) + pdst[j] = psrc[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); - psrc += 0x10; - pdst += 0x10; + psrc += 4; + pdst += 4; + } + + se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); + + pdst = (u32 *)dst; + + memcpy(tweak, temptweak, 0x10); + for (u32 i = 0; i < secsize / 0x10; i++) { + for (u32 j = 0; j < 4; j++) + pdst[j] = pdst[j] ^ ptweak[j]; + _gf256_mul_x_le(tweak); + pdst += 4; } res = 1; out:; + free(temptweak); free(tweak); return res; } From 9130c4b69c318a3eef388ad76ac97c7ceae3df51 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 8 May 2020 15:24:04 -0600 Subject: [PATCH 060/166] diskio: Improve emmc xts, double sector cache --- source/libs/fatfs/diskio.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 592d8f0..669ae1c 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -40,14 +40,14 @@ extern emmc_part_t *system_part; typedef struct { u32 sector; u32 visit_count; + u8 align[8]; u8 tweak[0x10]; u8 cached_sector[0x200]; - u8 align[8]; } sector_cache_t; -#define MAX_SEC_CACHE_ENTRIES 64 +#define MAX_SEC_CACHE_ENTRIES 128 static sector_cache_t *sector_cache = NULL; -static u32 secindex = 0; +u32 secindex = 0; bool clear_sector_cache = false; DSTATUS disk_status ( @@ -80,8 +80,10 @@ static inline void _gf256_mul_x_le(void *block) { static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) { int res = 0; - u8 *pdst = (u8 *)dst; - u8 *psrc = (u8 *)src; + u8 *temptweak = (u8 *)malloc(0x10); + u32 *pdst = (u32 *)dst; + u32 *psrc = (u32 *)src; + u32 *ptweak = (u32 *)tweak; if (regen_tweak) { for (int i = 0xF; i >= 0; i--) { @@ -95,34 +97,33 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe for (u32 i = 0; i < tweak_exp * 0x20; i++) _gf256_mul_x_le(tweak); - u8 temptweak[0x10]; memcpy(temptweak, tweak, 0x10); //We are assuming a 0x10-aligned sector size in this implementation. for (u32 i = 0; i < secsize / 0x10; i++) { - for (u32 j = 0; j < 0x10; j++) - pdst[j] = psrc[j] ^ tweak[j]; + for (u32 j = 0; j < 4; j++) + pdst[j] = psrc[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); - psrc += 0x10; - pdst += 0x10; + psrc += 4; + pdst += 4; } - se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize); + se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); - pdst = (u8 *)dst; + pdst = (u32 *)dst; memcpy(tweak, temptweak, 0x10); for (u32 i = 0; i < secsize / 0x10; i++) { - for (u32 j = 0; j < 0x10; j++) - pdst[j] = pdst[j] ^ tweak[j]; + for (u32 j = 0; j < 4; j++) + pdst[j] = pdst[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); - pdst += 0x10; + pdst += 4; } - res = 1; out:; + free(temptweak); return res; } From 3705b5f228634714ba085cc59d2b0039789c9a96 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 10 May 2020 13:28:54 -0600 Subject: [PATCH 061/166] Hardcode buffers, lock sector cache, use fastfs --- common/memory_map.h | 84 ++++++++------ source/keys/keys.c | 44 +++++--- source/libs/fatfs/diskio.c | 11 +- source/libs/fatfs/ff.c | 223 ++++++++++++++++++++++++++++++++++++- source/libs/fatfs/ff.h | 15 +++ source/libs/fatfs/ffconf.h | 5 + 6 files changed, 325 insertions(+), 57 deletions(-) diff --git a/common/memory_map.h b/common/memory_map.h index 271d9f7..a1a41cb 100644 --- a/common/memory_map.h +++ b/common/memory_map.h @@ -28,60 +28,74 @@ /* --- DRAM START --- */ #define DRAM_START 0x80000000 -/* 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 --- */ +#define HOS_RSVD 0x1000000 // Do not write anything in this area. -// SDMMC DMA buffers -#define SDXC_BUF_ALIGNED 0xB6000000 -#define MIXD_BUF_ALIGNED 0xB7000000 -#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED -#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). -#define SDMMC_UPPER_BUFFER 0xB8000000 -#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. +#define NYX_LOAD_ADDR 0x81000000 +#define NYX_SZ_MAX 0x1000000 // 16MB +/* --- Gap: 0x82000000 - 0x82FFFFFF --- */ + +/* Stack theoretical max: 33MB */ +#define IPL_STACK_TOP 0x83100000 +#define IPL_HEAP_START 0x84000000 +#define IPL_HEAP_SZ 0x20000000 // 512MB. +/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */ // Virtual disk / Chainloader buffers. -#define RAM_DISK_ADDR 0xC1000000 -#define RAM_DISK_SZ 0x20000000 +#define RAM_DISK_ADDR 0xA4000000 +#define RAM_DISK_SZ 0x41000000 // 1040MB. + //#define DRAM_LIB_ADDR 0xE0000000 /* --- 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. #define NYX_STORAGE_ADDR 0xED000000 #define NYX_RES_ADDR 0xEE000000 +#define NYX_RES_SZ 0x1000000 // 16MB. -// Framebuffer addresses. -#define IPL_FB_ADDRESS 0xF0000000 -#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. -#define LOG_FB_ADDRESS 0xF0400000 -#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. -#define NYX_FB_ADDRESS 0xF0800000 -#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. +// SDMMC DMA buffers 2 +#define SDXC_BUF_ALIGNED 0xEF000000 +#define MIXD_BUF_ALIGNED 0xF0000000 +#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED +#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). // 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_LV_MEM_ADR 0xF1000000 -#define NYX_LV_MEM_SZ 0x8000000 +#define NYX_LV_MEM_ADR 0xF1400000 +#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. -#define NX_BIS_CACHE_ADDR 0xF9000000 +#define NX_BIS_CACHE_ADDR 0xFEE00000 #define NX_BIS_CACHE_SZ 0x8800 -/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */ -// #define EXT_PAYLOAD_ADDR 0xC03C0000 -// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -// #define COREBOOT_ADDR (0xD0000000 - 0x100000) +// USB buffers. +#define USBD_ADDR 0xFEF00000 +#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 RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -// #define COREBOOT_ADDR (0xD0000000 - 0x100000) +// #define COREBOOT_ADDR (0xD0000000 - rom_size) #endif diff --git a/source/keys/keys.c b/source/keys/keys.c index 5cef76f..93d6c1a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -54,6 +54,8 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename); extern hekate_config h_cfg; extern bool clear_sector_cache; +extern bool lock_sector_cache; +extern u32 secindex; u32 _key_count = 0, _titlekey_count = 0; u32 color_idx = 0; @@ -580,6 +582,7 @@ pkg2_done: goto dismount; } + bool pkg1_not_100 = memcmp(pkg1_id->id, "2016", 4); path[25] = '/'; while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); @@ -594,7 +597,7 @@ pkg2_done: } se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); // es doesn't contain es key sources on 1.0.0 - if (memcmp(pkg1_id->id, "2016", 4) && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { + if (pkg1_not_100 && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { u8 hash_order[3] = {0, 1, 2}; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { hash_order[0] = 1; @@ -602,6 +605,7 @@ pkg2_done: } hash_index = 0; // decrypt only what is needed to locate needed keys + lock_sector_cache = true; temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); for (u32 i = 0; i <= 0xb0; ) { se_calc_sha256(temp_hash, temp_file + i, 0x10); @@ -618,7 +622,9 @@ pkg2_done: free(temp_file); temp_file = NULL; titles_found++; + lock_sector_cache = false; } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { + lock_sector_cache = true; temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); @@ -638,6 +644,7 @@ pkg2_done: free(temp_file); temp_file = NULL; titles_found++; + lock_sector_cache = false; } f_close(&fp); } @@ -717,8 +724,8 @@ get_titlekeys: se_aes_key_set(8, bis_key[0] + 0x00, 0x10); se_aes_key_set(9, bis_key[0] + 0x10, 0x10); - u32 buf_size = 0x4000; - u8 *buffer = (u8 *)malloc(buf_size); + u32 buf_size = 0x40000; + u8 *buffer = (u8 *)MIXD_BUF_ALIGNED; u8 keypair[0x230] = {0}; @@ -731,7 +738,6 @@ get_titlekeys: if (_read_le_u32(buffer, 0) != 0x304C4143) { EPRINTF("CAL0 magic not found. Check BIS key 0."); - free(buffer); goto dismount; } @@ -761,13 +767,11 @@ get_titlekeys: // Check public exponent is 0x10001 big endian if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { EPRINTF("Invalid public exponent."); - free(buffer); goto dismount; } if (!_test_key_pair(E, D, N)) { EPRINTF("Invalid keypair. Check eticket_rsa_kek."); - free(buffer); goto dismount; } @@ -776,25 +780,28 @@ get_titlekeys: u32 br = buf_size; u32 file_tkey_count = 0; u64 total_br = 0; - rights_ids = (u8 *)malloc(0x40000); - titlekeys = (u8 *)malloc(0x40000); + rights_ids = (u8 *)(MIXD_BUF_ALIGNED + 0x40000); + titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000); save_ctx = calloc(1, sizeof(save_ctx_t)); u8 M[0x100]; if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open e1 save. Skipping."); - free(buffer); goto dismount; } + DWORD *clmt = f_expand_cltbl(&fp, buf_size, 0); u32 pct = 0, last_pct = 0; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); + clear_sector_cache = true; save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e1 save."); + f_close(&fp); + free(clmt); goto dismount; } @@ -804,6 +811,8 @@ get_titlekeys: save_fs_list_entry_t entry = {0, "", {0}, 0}; if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { EPRINTF("Unable to locate ticket_list.bin in e1."); + f_close(&fp); + free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -819,6 +828,8 @@ get_titlekeys: } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { EPRINTF("Unable to locate ticket.bin in e1 save."); + f_close(&fp); + free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -859,21 +870,28 @@ get_titlekeys: u32 common_titlekey_count = _titlekey_count; if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open e2 save. Skipping."); - free(buffer); + free(clmt); goto dismount; } + fp.cltbl = clmt; + clmt = f_expand_cltbl(&fp, buf_size, 0); save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); + clear_sector_cache = true; save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e2 save."); + f_close(&fp); + free(clmt); goto dismount; } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { EPRINTF("Unable to locate ticket_list.bin in e2 save."); + f_close(&fp); + free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -892,6 +910,8 @@ get_titlekeys: } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { EPRINTF("Unable to locate ticket.bin in e2 save."); + f_close(&fp); + free(clmt); goto dismount; } @@ -930,8 +950,8 @@ get_titlekeys: } } tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); - free(buffer); f_close(&fp); + free(clmt); gfx_con_setpos(0, save_y); TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); @@ -1053,8 +1073,6 @@ key_output: ; EPRINTF("Unable to save titlekeys to SD."); free_buffers: - free(rights_ids); - free(titlekeys); free(text_buffer); out_wait: diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 669ae1c..2cfacd7 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -45,10 +45,11 @@ typedef struct { u8 cached_sector[0x200]; } sector_cache_t; -#define MAX_SEC_CACHE_ENTRIES 128 -static sector_cache_t *sector_cache = NULL; +#define MAX_SEC_CACHE_ENTRIES 256 +static sector_cache_t *sector_cache = (sector_cache_t *)(MIXD_BUF_ALIGNED + 0x100000); //NULL; u32 secindex = 0; bool clear_sector_cache = false; +bool lock_sector_cache = false; DSTATUS disk_status ( BYTE pdrv /* Physical drive number to identify the drive */ @@ -154,14 +155,14 @@ DRESULT disk_read ( bool needs_cache_sector = false; if (secindex == 0 || clear_sector_cache) { - if (!sector_cache) - sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); clear_sector_cache = false; + lock_sector_cache = false; secindex = 0; } u32 s = 0; - if (count == 1) { + // only attempt to cache single-sector reads as these are most likely to be repeated (eg. rereading FAT) + if (!lock_sector_cache && count == 1) { for ( ; s < secindex; s++) { if (sector_cache[s].sector == sector) { sector_cache[s].visit_count++; diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index c3e2ab9..c48c036 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -3906,6 +3906,93 @@ FRESULT f_read ( +#ifdef FF_FASTFS +/*-----------------------------------------------------------------------*/ +/* Fast Read Aligned Sized File Without a Cache */ +/*-----------------------------------------------------------------------*/ +#if FF_USE_FASTSEEK +FRESULT f_read_fast ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btr /* Number of bytes to read */ +) +{ + FRESULT res; + FATFS *fs; + UINT csize_bytes; + DWORD clst; + UINT count = 0; + FSIZE_t work_sector = 0; + FSIZE_t sector_base = 0; + BYTE *wbuff = (BYTE*)buff; + + // TODO support sector reading inside a cluster + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { + EFSPRINTF("FOV"); + LEAVE_FF(fs, res); /* Check validity */ + } + + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + FSIZE_t remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + csize_bytes = fs->csize * SS(fs); + + if (!fp->fptr) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + } else { + if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } + } + if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; /* Set working cluster */ + + sector_base = clst2sect(fs, fp->clust); + count += fs->csize; + btr -= csize_bytes; + fp->fptr += csize_bytes; + + while (btr) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + + if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; + + work_sector = clst2sect(fs, fp->clust); + if ((work_sector - sector_base) == count) count += fs->csize; + else { + if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + wbuff += count * SS(fs); + + sector_base = work_sector; + count = fs->csize; + } + + fp->fptr += MIN(btr, csize_bytes); + btr -= MIN(btr, csize_bytes); + + // TODO: what about if data is smaller than cluster? + // Must read-write back that cluster. + + if (!btr) { /* Final cluster/sectors read. */ + if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + } + + LEAVE_FF(fs, FR_OK); +} +#endif +#endif + + + + #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ @@ -4045,6 +4132,98 @@ FRESULT f_write ( +#ifdef FF_FASTFS +/*-----------------------------------------------------------------------*/ +/* Fast Write Aligned Sized File Without a Cache */ +/*-----------------------------------------------------------------------*/ +#if FF_USE_FASTSEEK +FRESULT f_write_fast ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw /* Number of bytes to write */ +) +{ + FRESULT res; + FATFS *fs; + UINT csize_bytes; + DWORD clst; + UINT count = 0; + FSIZE_t work_sector = 0; + FSIZE_t sector_base = 0; + const BYTE *wbuff = (const BYTE*)buff; + + // TODO support sector writing inside a cluster + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { + EFSPRINTF("FOV"); + LEAVE_FF(fs, res); /* Check validity */ + } + + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + csize_bytes = fs->csize * SS(fs); + + if (!fp->fptr) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + } else { + if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } + } + + if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; /* Set working cluster */ + + sector_base = clst2sect(fs, fp->clust); + count += fs->csize; + btw -= csize_bytes; + fp->fptr += csize_bytes; + + while (btw) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + + if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; + + work_sector = clst2sect(fs, fp->clust); + if ((work_sector - sector_base) == count) count += fs->csize; + else { + if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + wbuff += count * SS(fs); + + sector_base = work_sector; + count = fs->csize; + } + + fp->fptr += MIN(btw, csize_bytes); + btw -= MIN(btw, csize_bytes); + + // what about if data is smaller than cluster? + // Probably must read-write back that cluster. + if (!btw) { /* Final cluster/sectors write. */ + if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} +#endif +#endif + + + + /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ @@ -4501,6 +4680,39 @@ FRESULT f_lseek ( +#ifdef FF_FASTFS +#if FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* Seek File Read/Write Pointer */ +/*-----------------------------------------------------------------------*/ + +DWORD *f_expand_cltbl ( + FIL* fp, /* Pointer to the file object */ + UINT tblsz, /* Size of table */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ + if (!fp->cltbl) { /* Allocate memory for cluster link table */ + fp->cltbl = (DWORD *)ff_memalloc(tblsz); + fp->cltbl[0] = tblsz; + } + if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ + ff_memfree(fp->cltbl); + fp->cltbl = NULL; + EFSPRINTF("CLTBLSZ"); + return NULL; + } + f_lseek(fp, 0); + + return fp->cltbl; +} +#endif +#endif + + + + #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ @@ -5630,7 +5842,7 @@ FRESULT f_mkfs ( UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ @@ -5694,7 +5906,7 @@ FRESULT f_mkfs ( } else { /* Create a single-partition in this function */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } @@ -5918,6 +6130,9 @@ FRESULT f_mkfs ( if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ + if (n % n_fats) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } sz_fat += n / n_fats; } @@ -5981,13 +6196,13 @@ FRESULT f_mkfs ( st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ diff --git a/source/libs/fatfs/ff.h b/source/libs/fatfs/ff.h index f867131..6c47c73 100644 --- a/source/libs/fatfs/ff.h +++ b/source/libs/fatfs/ff.h @@ -246,7 +246,12 @@ typedef enum { FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ +#ifdef FF_FASTFS + FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ + FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */ +#else FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +#endif } FRESULT; @@ -258,6 +263,10 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +#ifdef FF_FASTFS +FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */ +FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */ +#endif FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ @@ -279,6 +288,9 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +#ifdef FF_FASTFS +DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */ +#endif FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ @@ -368,8 +380,11 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ +#define AM_DEV 0x40 /* Device */ +#define AM_RVD 0x80 /* Reserved */ #ifdef __cplusplus diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index dc9577e..ab7a198 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -41,8 +41,13 @@ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ +#define FF_FASTFS 1 +#ifdef FF_FASTFS +#define FF_USE_FASTSEEK 1 +#else #define FF_USE_FASTSEEK 0 +#endif /* This option switches fast seek function. (0:Disable or 1:Enable) */ From da6734afff48746e04a57467dd9f809c33d089d3 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 10 May 2020 19:10:27 -0600 Subject: [PATCH 062/166] save: Tidied up error prints --- source/keys/save.c | 34 +++++++++++++++++----------------- source/keys/save.h | 6 +----- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/source/keys/save.c b/source/keys/save.c index 7b0695a..763c45b 100644 --- a/source/keys/save.c +++ b/source/keys/save.c @@ -1,3 +1,4 @@ +#include #include #include "save.h" @@ -237,14 +238,14 @@ size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) { if (count > ctx->sector_size) { - EPRINTF("IVFC read exceeds sector size!\n"); + EPRINTF("IVFC read exceeds sector size!"); return; } uint64_t block_index = offset / ctx->sector_size; if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count); + EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!", (u32)offset, count); return; } @@ -285,7 +286,7 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf } if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count); + EPRINTFARGS("Hash error from current check\n found at offset %x count %x!", (u32)offset, count); return; } } @@ -297,7 +298,7 @@ uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ct allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE); if ((entries[0].next & 0x80000000) == 0) { if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) { - EPRINTF("Invalid range entry in allocation table!\n"); + EPRINTF("Invalid range entry in allocation table!"); return 0; } } else { @@ -330,7 +331,7 @@ uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint total_length += save_allocation_table_read_entry_with_length(ctx, &entry); nodes_iterated++; if (nodes_iterated > table_size) { - EPRINTF("Cycle detected in allocation table!\n"); + EPRINTF("Cycle detected in allocation table!"); return 0; } } @@ -357,7 +358,7 @@ void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, ctx->prev_block = entry.prev; if (ctx->prev_block != 0xFFFFFFFF) { - EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block); + EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!", initial_block); return; } } @@ -456,7 +457,7 @@ int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save return 1; } -uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) { +uint32_t save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) { save_fs_list_entry_t entry; uint32_t capacity = save_fs_list_get_capacity(ctx); save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry); @@ -483,18 +484,18 @@ uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_ return 0xFFFFFFFF; } -int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) { +int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, const char *path) { key->parent = 0; - char *pos = strchr(path, '/'); + const char *pos = strchr(path, '/'); while (pos) { memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); - char *tmp = strchr(pos, '/'); + const char *tmp = strchr(pos, '/'); if (!tmp) { memcpy(key->name, pos, strlen(pos)); break; } memcpy(key->name, pos, tmp - pos); - key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL); + key->parent = save_fs_list_get_index_from_key(&ctx->directory_table, key, NULL); if (key->parent == 0xFFFFFFFF) return 0; pos = tmp + 1; @@ -529,13 +530,13 @@ int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_tabl return 1; } -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry) { +int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_fs_list_entry_t *entry) { save_entry_key_t key; if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) { EPRINTF("Unable to locate file."); return 0; } - u32 index = save_fs_get_index_from_key(&ctx->file_table, &key, NULL); + u32 index = save_fs_list_get_index_from_key(&ctx->file_table, &key, NULL); if (index == 0xFFFFFFFF) { EPRINTF("Unable to get table index for file."); return 0; @@ -643,13 +644,12 @@ bool save_process(save_ctx_t *ctx) { } if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { - EPRINTF("Error: Save header is invalid!\n"); + EPRINTF("Error: Save header is invalid!"); return false; } } - unsigned char cmac[0x10]; - memset(cmac, 0, 0x10); + unsigned char cmac[0x10] = {}; se_aes_key_set(3, ctx->save_mac_key, 0x10); se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { @@ -775,7 +775,7 @@ bool save_process_header(save_ctx_t *ctx) { ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || ctx->header.meta_remap_header.magic != MAGIC_RMAP) { - EPRINTF("Error: Save header is corrupt!\n"); + EPRINTF("Error: Save header is corrupt!"); return false; } diff --git a/source/keys/save.h b/source/keys/save.h index f7006ca..c42b7bf 100644 --- a/source/keys/save.h +++ b/source/keys/save.h @@ -474,16 +474,12 @@ static inline uint32_t save_allocation_table_get_free_list_block_index(allocatio bool save_process(save_ctx_t *ctx); bool save_process_header(save_ctx_t *ctx); -void save_save(save_ctx_t *ctx); -void save_print(save_ctx_t *ctx); void save_free_contexts(save_ctx_t *ctx); void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index); uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count); int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value); -uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index); -int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path); -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry); +int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_fs_list_entry_t *entry); #endif From 2f6ee85d3750cce2515977182ddcd91592b903e0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 10 May 2020 19:10:47 -0600 Subject: [PATCH 063/166] main: Removed redundant defines --- source/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/main.c b/source/main.c index bb39156..3fcdf81 100644 --- a/source/main.c +++ b/source/main.c @@ -402,9 +402,6 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) { ment_top[1].caption = emunand_label; } -#define IPL_STACK_TOP 0x90010000 -#define IPL_HEAP_START 0x90020000 - extern void pivot_stack(u32 stack_top); void ipl_main() From c63532bfdc70dbf39ba3502c7e5c425edc29eefc Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 10 May 2020 19:11:07 -0600 Subject: [PATCH 064/166] keys: Fastfs wasn't appropriate for this after all --- source/keys/keys.c | 11 ----------- source/libs/fatfs/ffconf.h | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 93d6c1a..b72334c 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -789,7 +789,6 @@ get_titlekeys: goto dismount; } - DWORD *clmt = f_expand_cltbl(&fp, buf_size, 0); u32 pct = 0, last_pct = 0; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); @@ -801,7 +800,6 @@ get_titlekeys: if (!save_process_success) { EPRINTF("Failed to process e1 save."); f_close(&fp); - free(clmt); goto dismount; } @@ -812,7 +810,6 @@ get_titlekeys: if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { EPRINTF("Unable to locate ticket_list.bin in e1."); f_close(&fp); - free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -829,7 +826,6 @@ get_titlekeys: if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { EPRINTF("Unable to locate ticket.bin in e1 save."); f_close(&fp); - free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -870,12 +866,9 @@ get_titlekeys: u32 common_titlekey_count = _titlekey_count; if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open e2 save. Skipping."); - free(clmt); goto dismount; } - fp.cltbl = clmt; - clmt = f_expand_cltbl(&fp, buf_size, 0); save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); @@ -884,14 +877,12 @@ get_titlekeys: if (!save_process_success) { EPRINTF("Failed to process e2 save."); f_close(&fp); - free(clmt); goto dismount; } if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { EPRINTF("Unable to locate ticket_list.bin in e2 save."); f_close(&fp); - free(clmt); goto dismount; } save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); @@ -911,7 +902,6 @@ get_titlekeys: if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { EPRINTF("Unable to locate ticket.bin in e2 save."); f_close(&fp); - free(clmt); goto dismount; } @@ -951,7 +941,6 @@ get_titlekeys: } tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); f_close(&fp); - free(clmt); gfx_con_setpos(0, save_y); TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index ab7a198..cd8bef0 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -41,7 +41,7 @@ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define FF_FASTFS 1 +#define FF_FASTFS 0 #ifdef FF_FASTFS #define FF_USE_FASTSEEK 1 From 0427c99176453b4cef61842799bfec4ed33cc5e0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 10 May 2020 21:09:11 -0600 Subject: [PATCH 065/166] keys: Improve messaging for long run times --- source/keys/keys.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index b72334c..f54915b 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -165,6 +165,8 @@ void dump_keys() { goto out_wait; } + bool pkg1_not_100 = memcmp(pkg1_id->id, "2016", 4); + bool found_tsec_fw = false; for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) { if (*pos == 0xCF42004D) { @@ -468,7 +470,7 @@ get_tsec: ; u8 hash_index = 0; const u8 key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; - if (!memcmp(pkg1_id->id, "2016", 4)) { + if (!pkg1_not_100) { // 1.0.0 doesn't have SD keys at all and the first key isn't aligned with the rest memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); hash_index = 1; @@ -564,7 +566,7 @@ pkg2_done: u8 *dec_header = (u8*)malloc(0x600); char path[100] = "emmc:/Contents/registered"; u32 titles_found = 0, title_limit = 2, read_bytes = 0; - if (!memcmp(pkg1_id->id, "2016", 4)) + if (!pkg1_not_100) title_limit = 1; u8 *temp_file = NULL; @@ -573,16 +575,23 @@ pkg2_done: goto dismount; } + gfx_printf("%kSector cache... ", colors[(color_idx++) % 6]); // prepopulate /Contents/registered in decrypted sector cache while (!f_readdir(&dir, &fno) && fno.fname[0]) {} f_closedir(&dir); + TPRINTF(); + + if (pkg1_not_100) { + gfx_printf("%kES & SSL keys...", colors[(color_idx++) % 6]); + } else { + gfx_printf("%kSSL keys... ", colors[(color_idx++) % 6]); + } if (f_opendir(&dir, path)) { EPRINTF("Unable to open System:/Contents/registered."); goto dismount; } - bool pkg1_not_100 = memcmp(pkg1_id->id, "2016", 4); path[25] = '/'; while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); @@ -633,7 +642,7 @@ pkg2_done: // only get ssl_rsa_kek_source_x from SSL on 1.0.0 // we get it from ES on every other firmware // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 - if (!memcmp(pkg1_id->id, "2016", 4)) { + if (!pkg1_not_100) { se_calc_sha256(temp_hash, temp_file + i + 0x10, 0x10); if (!memcmp(temp_hash, ssl_hashes_sha256[0], 0x10)) memcpy(es_keys[2], temp_file + i + 0x10, 0x10); @@ -665,11 +674,7 @@ pkg2_done: se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); } - if (memcmp(pkg1_id->id, "2016", 4)) { - TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]); - } else { - TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]); - } + TPRINTF(); char private_path[200] = "sd:/"; if (emu_cfg.nintendo_path && (emu_cfg.enabled || !h_cfg.emummc_force_disable)) { @@ -790,7 +795,6 @@ get_titlekeys: } u32 pct = 0, last_pct = 0; - tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; From a5fe954ce7730ef0c2962c8015c78a30b689e567 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 17 May 2020 17:45:48 -0600 Subject: [PATCH 066/166] Add se functions, match Hekate brace style --- source/gfx/gfx.c | 6 ++- source/gfx/tui.c | 3 +- source/hos/sept.c | 3 +- source/main.c | 9 ++-- source/sec/se.c | 103 +++++++++++++++++++++++++++++++++++++++++++--- source/sec/se.h | 5 +++ 6 files changed, 117 insertions(+), 12 deletions(-) diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 6adb7be..4323e49 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -216,7 +216,8 @@ void gfx_putc(char c) cbuf++; } 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.y += 16; } @@ -250,7 +251,8 @@ void gfx_putc(char c) fb += gfx_ctxt.stride - 8; } gfx_con.x += 8; - if (gfx_con.x >= gfx_ctxt.width - 8) { + if (gfx_con.x >= gfx_ctxt.width - 8) + { gfx_con.x = 0; gfx_con.y += 8; } diff --git a/source/gfx/tui.c b/source/gfx/tui.c index cd3cea6..3b59569 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -147,7 +147,8 @@ void *tui_do_menu(menu_t *menu) gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); else gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); - if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) { + if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) + { if (cnt == idx) gfx_printf(" %s", menu->ents[cnt].caption); else diff --git a/source/hos/sept.c b/source/hos/sept.c index 1858533..2a30f16 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -107,7 +107,8 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) { + if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) + { free(tmp_cfg); goto error; } diff --git a/source/main.c b/source/main.c index 3fcdf81..5ad772d 100644 --- a/source/main.c +++ b/source/main.c @@ -320,7 +320,8 @@ void launch_tools() if (file_sec) { - if (memcmp("sd:/", file_sec, 4)) { + if (memcmp("sd:/", file_sec, 4)) + { memcpy(dir + strlen(dir), "/", 2); memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1); } @@ -371,7 +372,8 @@ ment_t ment_top[] = { menu_t menu_top = { ment_top, NULL, 0, 0 }; -void _get_key_generations(char *sysnand_label, char *emunand_label) { +void _get_key_generations(char *sysnand_label, char *emunand_label) +{ sdmmc_t sdmmc; sdmmc_storage_t storage; sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); @@ -384,7 +386,8 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) { if (pkg1_id) sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); ment_top[0].caption = sysnand_label; - if (h_cfg.emummc_force_disable) { + if (h_cfg.emummc_force_disable) + { free(pkg1); return; } diff --git a/source/sec/se.c b/source/sec/se.c index c5e19b3..d129eda 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -235,6 +235,16 @@ void se_aes_key_set(u32 ks, const void *key, u32 size) } } +void se_aes_iv_set(u32 ks, const void *iv, u32 size) +{ + u32 *data = (u32 *)iv; + for (u32 i = 0; i < size / 4; i++) + { + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; + } +} + void se_aes_key_read(u32 ks, void *key, u32 size) { u32 *data = (u32 *)key; @@ -321,6 +331,83 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s return 1; } +// random calls were derived from Atmosphère's +int se_initialize_rng(u32 ks) +{ + u8 *output_buf = (u8 *)malloc(0x10); + + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001; + SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(DRBG_RO_ENT_SRC_LOCK_ENABLE) | + SE_RNG_SRC_CONFIG_RO_ENT_SRC(DRBG_RO_ENT_SRC_LOCK_ENABLE); + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + + int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0); + + free(output_buf); + return res; +} + +int se_generate_random(u32 ks, void *dst, u32 size) +{ + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + + u32 num_blocks = size >> 4; + u32 aligned_size = num_blocks << 4; + if (num_blocks) + { + SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 1; + if (!_se_execute(OP_START, dst, aligned_size, NULL, 0)) + return 0; + } + if (size > aligned_size) + return _se_execute_one_block(OP_START, dst + aligned_size, size - aligned_size, NULL, 0); + return 1; +} + +int se_generate_random_key(u32 ks_dst, u32 ks_src) +{ + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + + SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); + if (!_se_execute(OP_START, NULL, 0, NULL, 0)) + return 0; + SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1; + if (!_se_execute(OP_START, NULL, 0, NULL, 0)) + return 0; + + return 1; +} + +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | + SE_CRYPTO_IV_SEL(IV_ORIGINAL); + } + else + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) | + SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | + SE_CRYPTO_IV_SEL(IV_ORIGINAL); + } + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + return _se_execute(OP_START, dst, dst_size, src, src_size); +} + int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize) { int res = 0; @@ -356,7 +443,8 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo pdst = (u32 *)dst; memcpy(tweak, temptweak, 0x10); - for (u32 i = 0; i < secsize / 0x10; i++) { + for (u32 i = 0; i < secsize / 0x10; i++) + { for (u32 j = 0; j < 4; j++) pdst[j] = pdst[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); @@ -404,17 +492,21 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) se_aes_key_iv_clear(ks); u32 num_blocks = (src_size + 0xf) >> 4; - if (num_blocks > 1) { + if (num_blocks > 1) + { SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2; if (!_se_execute(OP_START, NULL, 0, src, src_size)) goto out; SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED); } - if (src_size & 0xf) { + if (src_size & 0xf) + { memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf); last_block[src_size & 0xf] = 0x80; - } else if (src_size >= 0x10) { + } + else if (src_size >= 0x10) + { memcpy(last_block, src + src_size - 0x10, 0x10); } @@ -461,7 +553,8 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) return res; } -int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) { +int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) +{ int res = 0; u8 *secret = (u8 *)malloc(0x40); u8 *ipad = (u8 *)malloc(0x40 + src_size); diff --git a/source/sec/se.h b/source/sec/se.h index 0d517c7..211c279 100644 --- a/source/sec/se.h +++ b/source/sec/se.h @@ -25,12 +25,17 @@ void se_rsa_key_clear(u32 ks); int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); void se_key_acc_ctrl(u32 ks, u32 flags); void se_aes_key_set(u32 ks, const void *key, u32 size); +void se_aes_iv_set(u32 ks, const void *iv, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size); void se_aes_key_clear(u32 ks); +int se_initialize_rng(u32 ks); +int se_generate_random(u32 ks, void *dst, u32 size); +int se_generate_random_key(u32 ks_dst, u32 ks_src); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize); int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); From 64d7e5cebd2ee8d4b37173a66aeae48ec88b7981 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 18 May 2020 14:11:27 -0600 Subject: [PATCH 067/166] Apply hekate 5.2.1 and gcc 10 changes, -fno-inline --- Makefile | 2 +- source/config/config.c | 565 +--------- source/config/ini.c | 7 +- source/gfx/di.c | 164 ++- source/gfx/di.h | 171 +++- source/gfx/di.inl | 224 ++-- source/gfx/gfx.c | 6 +- source/gfx/gfx.h | 8 +- source/gfx/tui.h | 2 +- source/hos/fss.c | 247 +++++ source/hos/fss.h | 34 + source/hos/hos.h | 120 +++ source/hos/pkg2.c | 4 + source/hos/pkg2.h | 22 +- source/hos/sept.c | 3 +- source/ianos/ianos.c | 11 +- source/keys/keys.c | 14 +- source/keys/save.c | 6 +- source/libs/compr/blz.c | 1 + source/libs/fatfs/ffconf.h | 2 +- source/main.c | 91 +- source/mem/emc.h | 1212 +++++++++++----------- source/mem/heap.c | 4 +- source/mem/mc_t210.h | 50 + source/mem/minerva.c | 3 +- source/mem/minerva.h | 2 +- source/mem/sdram.c | 125 ++- source/mem/sdram.h | 2 + source/mem/sdram_config.inl | 1811 ++++++++++++--------------------- source/mem/sdram_param_t210.h | 10 +- source/power/max17050.h | 3 + source/sec/se.c | 16 +- source/sec/se_t210.h | 40 +- source/sec/tsec.c | 1 + source/soc/bpmp.c | 150 ++- source/soc/bpmp.h | 23 +- source/soc/clock.c | 209 +++- source/soc/clock.h | 44 +- source/soc/fuse.h | 2 + source/soc/gpio.c | 168 ++- source/soc/gpio.h | 20 +- source/soc/hw_init.c | 5 +- source/soc/i2c.c | 37 +- source/soc/irq.c | 263 +++++ source/soc/irq.h | 222 ++++ source/soc/pinmux.h | 1 + source/soc/pmc.h | 12 + source/soc/t210.h | 75 +- source/storage/emummc.c | 29 +- source/storage/emummc.h | 4 +- source/storage/mbr_gpt.h | 84 ++ source/storage/nx_emmc.c | 28 +- source/storage/nx_emmc.h | 32 +- source/storage/nx_sd.c | 184 ++++ source/storage/nx_sd.h | 45 + source/storage/sd.h | 5 + source/storage/sdmmc.c | 275 +++-- source/storage/sdmmc.h | 16 +- source/storage/sdmmc_driver.c | 727 +++++++------ source/storage/sdmmc_driver.h | 194 +++- source/storage/sdmmc_t210.h | 110 +- source/utils/types.h | 26 +- source/utils/util.c | 45 +- source/utils/util.h | 18 +- 64 files changed, 4676 insertions(+), 3360 deletions(-) create mode 100644 source/hos/fss.c create mode 100644 source/hos/fss.h create mode 100644 source/hos/hos.h create mode 100644 source/soc/irq.c create mode 100644 source/soc/irq.h create mode 100644 source/storage/mbr_gpt.h create mode 100644 source/storage/nx_sd.c create mode 100644 source/storage/nx_sd.h diff --git a/Makefile b/Makefile index d810cec..0dddc20 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fno-inline -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) ################################################################################ diff --git a/source/config/config.c b/source/config/config.c index 23b516f..5028b08 100644 --- a/source/config/config.c +++ b/source/config/config.c @@ -23,14 +23,13 @@ #include "../gfx/tui.h" #include "../libs/fatfs/ff.h" #include "../soc/t210.h" +#include "../storage/nx_sd.h" #include "../storage/sdmmc.h" #include "../utils/btn.h" #include "../utils/list.h" #include "../utils/util.h" extern hekate_config h_cfg; -extern bool sd_mount(); -extern void sd_unmount(); void set_default_configuration() { @@ -52,565 +51,3 @@ void set_default_configuration() sd_power_cycle_time_start = 0; } - -int create_config_entry() -{ - if (!sd_mount()) - return 1; - - char lbuf[32]; - FIL fp; - bool mainIniFound = false; - - LIST_INIT(ini_sections); - - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - mainIniFound = true; - else - { - u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); - if (res == FR_NO_FILE || res == FR_NO_PATH) - { - f_mkdir("bootloader"); - f_mkdir("bootloader/ini"); - f_mkdir("bootloader/payloads"); - f_mkdir("bootloader/sys"); - } - else - { - if (!res) - f_close(&fp); - return 1; - } - } - - if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) - return 1; - // Add config entry. - f_puts("[config]\nautoboot=", &fp); - itoa(h_cfg.autoboot, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautoboot_list=", &fp); - itoa(h_cfg.autoboot_list, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbootwait=", &fp); - itoa(h_cfg.bootwait, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbacklight=", &fp); - itoa(h_cfg.backlight, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautohosoff=", &fp); - itoa(h_cfg.autohosoff, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautonogc=", &fp); - itoa(h_cfg.autonogc, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nupdater2p=", &fp); - itoa(h_cfg.updater2p, lbuf, 10); - f_puts(lbuf, &fp); - if (h_cfg.brand) - { - f_puts("\nbrand=", &fp); - f_puts(h_cfg.brand, &fp); - } - if (h_cfg.tagline) - { - f_puts("\ntagline=", &fp); - f_puts(h_cfg.tagline, &fp); - } - f_puts("\n", &fp); - - if (mainIniFound) - { - // Re-construct existing entries. - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - switch (ini_sec->type) - { - case INI_CHOICE: // Re-construct Boot entry [ ]. - f_puts("[", &fp); - f_puts(ini_sec->name, &fp); - f_puts("]\n", &fp); - // Re-construct boot entry's config. - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - f_puts(kv->key, &fp); - f_puts("=", &fp); - f_puts(kv->val, &fp); - f_puts("\n", &fp); - } - break; - case INI_CAPTION: // Re-construct caption entry { }. - f_puts("{", &fp); - f_puts(ini_sec->name, &fp); - f_puts("}\n", &fp); - break; - case INI_NEWLINE: // Re-construct cosmetic newline \n. - f_puts("\n", &fp); - break; - case INI_COMMENT: // Re-construct comment entry #. - f_puts("#", &fp); - f_puts(ini_sec->name, &fp); - f_puts("\n", &fp); - break; - } - } - } - - f_close(&fp); - sd_unmount(); - - return 0; -} - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -static void _save_config() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - if (!create_config_entry()) - gfx_puts("\nConfiguration was saved!\n"); - else - EPRINTF("\nConfiguration saving failed!"); - gfx_puts("\nPress any key..."); -} - -static void _config_autoboot_list(void *ent) -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(512 * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/ini", true)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 2; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) - boot_text[(i - 1) * 512] = ' '; - - else - boot_text[(i - 1) * 512] = '*'; - strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 1) * 512]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 1]; - i++; - - if ((i - 1) > max_entries) - break; - } - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 1; - _save_config(); - - ment_t *tmp = (ment_t *)ent; - tmp->data = NULL; - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); -} - -void config_autoboot() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - u32 boot_text_size = 512; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(boot_text_size * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (!h_cfg.autoboot) - ments[2].caption = "*Disable"; - else - ments[2].caption = " Disable"; - ments[2].data = &boot_values[0]; - - ments[3].type = MENT_HDLR_RE; - if (h_cfg.autoboot_list) - ments[3].caption = "*More configs..."; - else - ments[3].caption = " More configs..."; - ments[3].handler = _config_autoboot_list; - ments[3].data = (void *)0xCAFE; - - ments[4].type = MENT_CHGLINE; - - u32 i = 5; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) - boot_text[(i - 4) * boot_text_size] = ' '; - - else - boot_text[(i - 4) * boot_text_size] = '*'; - strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 4) * boot_text_size]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 4]; - i++; - - if ((i - 4) > max_entries) - break; - } - } - if (i < 6 && !h_cfg.autoboot_list) - { - ments[i].type = MENT_CAPTION; - ments[i].caption = "No main configurations found..."; - ments[i].color = 0xFFFFDD00; - i++; - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 0; - _save_config(); - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); - - if (temp_autoboot == NULL) - return; -} - -void config_bootdelay() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 delay_entries = 6; - u32 delay_text_size = 32; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); - u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); - char *delay_text = (char *)malloc(delay_text_size * delay_entries); - - for (u32 j = 0; j < delay_entries; j++) - delay_values[j] = j; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (h_cfg.bootwait) - ments[2].caption = " 0 seconds (Bootlogo disabled)"; - else - ments[2].caption = "*0 seconds (Bootlogo disabled)"; - ments[2].data = &delay_values[0]; - - u32 i = 0; - for (i = 1; i < delay_entries; i++) - { - if (h_cfg.bootwait != i) - delay_text[i * delay_text_size] = ' '; - else - delay_text[i * delay_text_size] = '*'; - delay_text[i * delay_text_size + 1] = i + '0'; - strcpy(delay_text + i * delay_text_size + 2, " seconds"); - - ments[i + 2].type = MENT_DATA; - ments[i + 2].caption = delay_text + (i * delay_text_size); - ments[i + 2].data = &delay_values[i]; - } - - memset(&ments[i + 2], 0, sizeof(ment_t)); - menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; - - u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); - if (temp_bootwait != NULL) - { - h_cfg.bootwait = *(u32 *)temp_bootwait; - _save_config(); - } - - free(ments); - free(delay_values); - free(delay_text); - - if (temp_bootwait == NULL) - return; - btn_wait(); -} - -void config_backlight() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 bri_text_size = 8; - u32 bri_entries = 11; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); - u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); - char *bri_text = (char *)malloc(bri_text_size * bri_entries); - - for (u32 j = 1; j < bri_entries; j++) - bri_values[j] = j * 10; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 0; - for (i = 1; i < bri_entries; i++) - { - if ((h_cfg.backlight / 20) != i) - bri_text[i * bri_text_size] = ' '; - else - bri_text[i * bri_text_size] = '*'; - - if (i < 10) - { - bri_text[i * bri_text_size + 1] = i + '0'; - strcpy(bri_text + i * bri_text_size + 2, "0%"); - } - else - strcpy(bri_text + i * bri_text_size + 1, "100%"); - - ments[i + 1].type = MENT_DATA; - ments[i + 1].caption = bri_text + (i * bri_text_size); - ments[i + 1].data = &bri_values[i]; - } - - memset(&ments[i + 1], 0, sizeof(ment_t)); - menu_t menu = {ments, "Backlight brightness", 0, 0}; - - u32 *temp_backlight = (u32 *)tui_do_menu(&menu); - if (temp_backlight != NULL) - { - h_cfg.backlight = (*(u32 *)temp_backlight) * 2; - _save_config(); - } - - free(ments); - free(bri_values); - free(bri_text); - - if (temp_backlight == NULL) - return; - btn_wait(); -} - -void config_auto_hos_poweroff() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); - u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); - - for (u32 j = 0; j < 3; j++) - { - hp_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &hp_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autohosoff == 1) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Enable"; - ments[4].caption = " Enable (No logo)"; - } - else if (h_cfg.autohosoff >= 2) - { - ments[2].caption = " Disable"; - ments[3].caption = " Enable"; - ments[4].caption = "*Enable (No logo)"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Enable"; - ments[4].caption = " Enable (No logo)"; - } - - memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; - - u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); - if (temp_autohosoff != NULL) - { - h_cfg.autohosoff = *(u32 *)temp_autohosoff; - _save_config(); - } - - free(ments); - free(hp_values); - - if (temp_autohosoff == NULL) - return; - btn_wait(); -} - -void config_nogc() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); - u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); - - for (u32 j = 0; j < 2; j++) - { - cb_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &cb_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autonogc) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Auto"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Auto"; - } - - memset(&ments[4], 0, sizeof(ment_t)); - menu_t menu = {ments, "No Gamecard", 0, 0}; - - u32 *temp_nogc = (u32 *)tui_do_menu(&menu); - if (temp_nogc != NULL) - { - h_cfg.autonogc = *(u32 *)temp_nogc; - _save_config(); - } - - free(ments); - free(cb_values); - - if (temp_nogc == NULL) - return; - btn_wait(); -} - -#pragma GCC pop_options diff --git a/source/config/ini.c b/source/config/ini.c index 85a19b1..4c200dd 100644 --- a/source/config/ini.c +++ b/source/config/ini.c @@ -55,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) { if (csec) - { 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->type = type; @@ -154,7 +151,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) { 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->val = _strdup(&lbuf[i + 1]); list_append(&csec->kvs, &kv->link); diff --git a/source/gfx/di.c b/source/gfx/di.c index 200d412..3252475 100644 --- a/source/gfx/di.c +++ b/source/gfx/di.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -31,7 +31,11 @@ #include "di.inl" -static u32 _display_ver = 0; +extern volatile nyx_storage_t *nyx_str; + +static u32 _display_id = 0; + +void display_end(); static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) { @@ -41,8 +45,21 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) usleep(5); } +static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait) +{ + DSI(_DSIREG(DSI_WR_DATA)) = (param << 8) | cmd; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + + if (wait) + usleep(wait); +} + void display_init() { + // Check if display is already initialized. + if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & 0x18000000) + display_end(); + // Power on. max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); @@ -60,16 +77,16 @@ void display_init() CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). - // Disable deap power down. + // Disable deep power down. PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; // Config LCD and Backlight pins. - PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; // PULL_DOWN | 1 + PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; // PULL_DOWN // Set Backlight +-5V pins mode and direction gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); @@ -87,14 +104,18 @@ void display_init() gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. // Power up supply regulator for display interface. - MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0; + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0; - // Set DISP1 clock source and parrent clock. - exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4); + // Set DISP1 clock source and parent clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT. + u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 96 MHz. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP. + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2D0AAA; // PLLD_ENABLE_CLK. // Setup display communication interfaces. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94); - exec_cfg((u32 *)DSI_BASE, _display_config_3, 61); + exec_cfg((u32 *)DISPLAY_A_BASE, _display_dc_setup_win_config, 94); + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config, 61); usleep(10000); // Enable Backlight Reset. @@ -103,12 +124,10 @@ void display_init() // Setups DSI packet configuration and request display id. DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; - DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + _display_dsi_send_cmd(MIPI_DSI_DCS_READ, MIPI_DCS_GET_DISPLAY_ID, 0); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; @@ -116,37 +135,71 @@ void display_init() usleep(5000); - _display_ver = DSI(_DSIREG(DSI_RD_DATA)); - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_4, 43); + // MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 u32. + for (u32 i = 0; i < 3; i++) + _display_id = DSI(_DSIREG(DSI_RD_DATA)); // Skip ack and msg type info and get the payload (display id). - DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + // Save raw Display ID to Nyx storage. + nyx_str->info.disp_id = _display_id; - usleep(180000); + // Decode Display ID. + _display_id = ((_display_id >> 8) & 0xFF00) | (_display_id & 0xFF); - DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + if ((_display_id & 0xFF) == PANEL_JDI_LPM062M) + _display_id = PANEL_JDI_LPM062M; - usleep(20000); + // Initialize display panel. + switch (_display_id) + { + case PANEL_JDI_LPM062M: + exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + break; + case PANEL_INL_P062CCA_AZ1: + case PANEL_AUO_A062TAN01: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + DSI(_DSIREG(DSI_WR_DATA)) = 0x739; // MIPI_DSI_DCS_LONG_WRITE: 7 bytes. + if (_display_id == PANEL_INL_P062CCA_AZ1) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + DSI(_DSIREG(DSI_WR_DATA)) = 0x143209; // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + case PANEL_INL_P062CCA_AZ2: + case PANEL_AUO_A062TAN02: + default: // Allow spare part displays to work. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000); + break; + } + + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); // Configure PLLD for DISP1. - exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3); + plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 460.8 MHz. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN. // Finalize DSI configuration. - exec_cfg((u32 *)DSI_BASE, _display_config_5, 21); - DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; - exec_cfg((u32 *)DSI_BASE, _display_config_7, 10); + exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 21); + DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; // PCD1 | div3. + exec_cfg((u32 *)DSI_BASE, _display_dsi_mode_config, 10); usleep(10000); // Calibrate display communication pads. - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6); - exec_cfg((u32 *)DSI_BASE, _display_config_9, 4); - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16); + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_pad_cal_config, 6); + exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config, 4); + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_apply_dsi_cal_config, 16); usleep(10000); // Enable video display controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113); + exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_enable_config, 113); } void display_backlight_pwm_init() @@ -197,25 +250,50 @@ void display_end() { display_backlight_brightness(0, 1000); - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1; + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE; DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. // De-initialize video controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17); - exec_cfg((u32 *)DSI_BASE, _display_config_13, 16); + exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17); + exec_cfg((u32 *)DSI_BASE, _display_dsi_timing_deinit_config, 16); usleep(10000); // De-initialize display panel. - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_14, 22); + switch (_display_id) + { + case PANEL_JDI_LPM062M: + exec_cfg((u32 *)DSI_BASE, _display_deinit_config_jdi, 22); + break; + case PANEL_AUO_A062TAN01: + exec_cfg((u32 *)DSI_BASE, _display_deinit_config_auo, 37); + break; + case PANEL_INL_P062CCA_AZ2: + case PANEL_AUO_A062TAN02: + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + // Set Power. + DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + if (_display_id == PANEL_INL_P062CCA_AZ2) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // Set Power control. (Unknown). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + case PANEL_INL_P062CCA_AZ1: + default: + break; + } - DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(50000); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, 50000); // Disable display and backlight pins. gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. diff --git a/source/gfx/di.h b/source/gfx/di.h index ee796a7..a160eff 100644 --- a/source/gfx/di.h +++ b/source/gfx/di.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -24,6 +24,21 @@ /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) +// Display controller scratch registers. +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_0 0xED +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_1 0xEE +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_0 0x16D +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_1 0x16E +#define DC_COM_SCRATCH_REGISTER_A 0x325 +#define DC_COM_SCRATCH_REGISTER_B 0x326 +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_0 0xBED +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_1 0xBEE +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_0 0xDED +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_1 0xDEE +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_0 0xFED +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_1 0xFEE + +// DC_CMD non-shadowed command/sync registers. #define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 @@ -50,6 +65,7 @@ #define PM0_ENABLE (1 << 16) #define PM1_ENABLE (1 << 18) +#define DC_CMD_INT_STATUS 0x37 #define DC_CMD_INT_MASK 0x38 #define DC_CMD_INT_ENABLE 0x39 @@ -62,11 +78,13 @@ #define WIN_A_ACT_REQ (1 << 1) #define WIN_B_ACT_REQ (1 << 2) #define WIN_C_ACT_REQ (1 << 3) +#define WIN_D_ACT_REQ (1 << 4) #define CURSOR_ACT_REQ (1 << 7) #define GENERAL_UPDATE (1 << 8) #define WIN_A_UPDATE (1 << 9) #define WIN_B_UPDATE (1 << 10) #define WIN_C_UPDATE (1 << 11) +#define WIN_D_UPDATE (1 << 12) #define CURSOR_UPDATE (1 << 15) #define NC_HOST_TRIG (1 << 24) @@ -74,15 +92,38 @@ #define WINDOW_A_SELECT (1 << 4) #define WINDOW_B_SELECT (1 << 5) #define WINDOW_C_SELECT (1 << 6) +#define WINDOW_D_SELECT (1 << 7) #define DC_CMD_REG_ACT_CONTROL 0x043 +// DC_D_WIN_DD window D instance of DC_WIN +#define DC_D_WIN_DD_WIN_OPTIONS 0x80 +#define DC_D_WIN_DD_COLOR_DEPTH 0x83 +#define DC_D_WIN_DD_POSITION 0x84 +#define DC_D_WIN_DD_SIZE 0x85 +#define DC_D_WIN_DD_LINE_STRIDE 0x8A +#define DC_D_WIN_DD_BLEND_LAYER_CONTROL 0x96 +#define DC_D_WIN_DD_BLEND_MATCH_SELECT 0x97 +#define DC_D_WIN_DD_BLEND_ALPHA_1BIT 0x99 + +// DC_D_WINBUF_DD window D instance of DC_WINBUF +#define DC_D_WINBUF_DD_START_ADDR 0xC0 +#define DC_D_WINBUF_DD_ADDR_H_OFFSET 0xC6 +#define DC_D_WINBUF_DD_ADDR_V_OFFSET 0xC8 +#define DC_D_WINBUF_DD_START_ADDR_HI 0xCD +#define DC_D_WINBUF_DD_MEMFETCH_CONTROL 0xEB + +// DC_T_WIN_TD macro for using DD defines. +#define _DC_T(reg) ((reg) + 0x80) + +// DC_COM non-shadowed registers. #define DC_COM_CRC_CONTROL 0x300 #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) #define DC_COM_DSC_TOP_CTL 0x33E +// DC_DISP shadowed registers. #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) #define DSI_ENABLE (1 << 29) @@ -161,6 +202,32 @@ #define DE_CONTROL_EARLY (3 << 2) #define DE_CONTROL_ACTIVE_BLANK (4 << 2) +// Cursor configuration registers. +#define DC_DISP_CURSOR_FOREGROUND 0x43C +#define DC_DISP_CURSOR_BACKGROUND 0x43D +#define CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16)) + +#define DC_DISP_CURSOR_START_ADDR 0x43E +#define CURSOR_CLIPPING(w) ((w) << 28) +#define CURSOR_CLIP_WIN_A 1 +#define CURSOR_CLIP_WIN_B 2 +#define CURSOR_CLIP_WIN_C 3 +#define CURSOR_SIZE_32 (0 << 24) +#define CURSOR_SIZE_64 (1 << 24) +#define CURSOR_SIZE_128 (2 << 24) +#define CURSOR_SIZE_256 (3 << 24) +#define DC_DISP_CURSOR_POSITION 0x440 +#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC +#define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1 +#define CURSOR_BLEND_2BIT (0 << 24) +#define CURSOR_BLEND_R8G8B8A8 (1 << 24) +#define CURSOR_BLEND_SRC_FACTOR(n) ((n) << 8) +#define CURSOR_BLEND_DST_FACTOR(n) ((n) << 16) +#define CURSOR_BLEND_ZRO 0 +#define CURSOR_BLEND_K1 1 +#define CURSOR_BLEND_NK1 2 +// End of cursor cfg regs. + #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 #define DC_DISP_SD_BL_PARAMETERS 0x4D7 #define DC_DISP_SD_BL_CONTROL 0x4DC @@ -187,6 +254,13 @@ #define CSC_ENABLE (1 << 18) #define WIN_ENABLE (1 << 30) +#define DC_WIN_BUFFER_CONTROL 0x702 +#define BUFFER_CONTROL_HOST 0 +#define BUFFER_CONTROL_VI 1 +#define BUFFER_CONTROL_EPP 2 +#define BUFFER_CONTROL_MPEGE 3 +#define BUFFER_CONTROL_SB2D 4 + #define DC_WIN_COLOR_DEPTH 0x703 #define WIN_COLOR_DEPTH_P1 0x0 #define WIN_COLOR_DEPTH_P2 0x1 @@ -211,8 +285,9 @@ #define WIN_COLOR_DEPTH_YCbCr422RA 0x18 #define WIN_COLOR_DEPTH_YUV422RA 0x19 -#define DC_WIN_BUFFER_CONTROL 0x702 #define DC_WIN_POSITION 0x704 +#define H_POSITION(x) (((x) & 0xFfff) << 0) +#define V_POSITION(x) (((x) & 0x1fff) << 16) #define DC_WIN_SIZE 0x705 #define H_SIZE(x) (((x) & 0x1fff) << 0) @@ -234,6 +309,42 @@ #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E +#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716 +#define WIN_K1(x) (((x) & 0xff) << 8) +#define WIN_K2(x) (((x) & 0xff) << 16) +#define WIN_BLEND_ENABLE (0 << 24) +#define WIN_BLEND_BYPASS (1 << 24) + +#define DC_WINBUF_BLEND_MATCH_SELECT 0x717 +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ZERO (0 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ONE (1 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 (2 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_DST (3 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (4 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC (5 << 0) + +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ZERO (0 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ONE (1 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1 (2 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K2 (3 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1_TIMES_DST (4 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (5 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC (6 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 (7 << 4) + +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_ZERO (0 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K1 (1 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 (2 << 8) + +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO (0 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ONE (1 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_NEG_K1_TIMES_SRC (2 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12) + +#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719 +#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xff) << 0) +#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xff) << 8) + /*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 @@ -336,6 +447,7 @@ #define DSI_PAD_CONTROL_CD 0x4C #define DSI_VIDEO_MODE_CONTROL 0x4E +#define DSI_CMD_PKT_VID_ENABLE 1 #define DSI_PAD_CONTROL_1 0x4F #define DSI_PAD_CONTROL_2 0x50 @@ -349,7 +461,57 @@ #define DSI_PAD_CONTROL_4 0x52 #define DSI_INIT_SEQ_DATA_15 0x5F -#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60 +/*! MIPI registers. */ +#define MIPI_CAL_MIPI_CAL_CTRL (0x00 / 0x4) +#define MIPI_CAL_CIL_MIPI_CAL_STATUS (0x08 / 0x4) +#define MIPI_CAL_CILA_MIPI_CAL_CONFIG (0x14 / 0x4) +#define MIPI_CAL_CILB_MIPI_CAL_CONFIG (0x18 / 0x4) +#define MIPI_CAL_CILC_MIPI_CAL_CONFIG (0x1C / 0x4) +#define MIPI_CAL_CILD_MIPI_CAL_CONFIG (0x20 / 0x4) +#define MIPI_CAL_CILE_MIPI_CAL_CONFIG (0x24 / 0x4) +#define MIPI_CAL_CILF_MIPI_CAL_CONFIG (0x28 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG (0x38 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG (0x3C / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG (0x40 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG (0x44 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 (0x58 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 (0x5C / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 (0x60 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 (0x64 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 (0x68 / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 (0x70 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4) + +/*! MIPI CMDs. */ +#define MIPI_DSI_DCS_SHORT_WRITE 0x05 +#define MIPI_DSI_DCS_READ 0x06 +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 +#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37 +#define MIPI_DSI_DCS_LONG_WRITE 0x39 + +/*! MIPI DCS CMDs. */ +#define MIPI_DCS_GET_DISPLAY_ID 0x04 +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10 +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11 +#define MIPI_DCS_SET_DISPLAY_ON 0x29 + +/* Switch Panels: + * [10] 81 [26]: JDI LPM062M326A + * [10] 96 [09]: JDI LAM062M109A + * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) + * [20] XX [10]: InnoLux P062CCA-AZ2 [UNCONFIRMED ID] + * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) + * [30] XX [10]: AUO A062TAN02 (59.06A33.002) [UNCONFIRMED ID] + */ + +enum +{ + PANEL_JDI_LPM062M = 0x10, + PANEL_INL_P062CCA_AZ1 = 0x0F20, + PANEL_AUO_A062TAN01 = 0x0F30, + PANEL_INL_P062CCA_AZ2 = 0x1020, + PANEL_AUO_A062TAN02 = 0x1030 +}; void display_init(); void display_backlight_pwm_init(); @@ -364,5 +526,8 @@ void display_backlight_brightness(u32 brightness, u32 step_delay); /*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ u32 *display_init_framebuffer(); +void display_init_cursor(void *crs_fb, u32 size); +void display_set_pos_cursor(u32 x, u32 y); +void display_deinit_cursor(); #endif diff --git a/source/gfx/di.inl b/source/gfx/di.inl index dd82899..9a275eb 100644 --- a/source/gfx/di.inl +++ b/source/gfx/di.inl @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer +* Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -15,16 +15,8 @@ * along with this program. If not, see . */ -//Clock config. -static const cfg_op_t _display_config_1[4] = { - {0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 - {0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC -}; - //Display A config. -static const cfg_op_t _display_config_2[94] = { +static const cfg_op_t _display_dc_setup_win_config[94] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, @@ -128,7 +120,7 @@ static const cfg_op_t _display_config_2[94] = { }; //DSI Init config. -static const cfg_op_t _display_config_3[61] = { +static const cfg_op_t _display_dsi_init_config[61] = { {DSI_WR_DATA, 0}, {DSI_INT_ENABLE, 0}, {DSI_INT_STATUS, 0}, @@ -192,14 +184,14 @@ static const cfg_op_t _display_config_3[61] = { {DSI_INIT_SEQ_CONTROL, 0} }; -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_4[43] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, +//DSI panel config. +static const cfg_op_t _display_init_config_jdi[43] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1939}, + {DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes. {DSI_WR_DATA, 0xAAAAAAD8}, {DSI_WR_DATA, 0xAAAAAAEB}, {DSI_WR_DATA, 0xAAEBAAAA}, @@ -208,9 +200,9 @@ static const cfg_op_t _display_config_4[43] = { {DSI_WR_DATA, 0xAAEBAAAA}, {DSI_WR_DATA, 0xAA}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1BD15}, + {DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x1BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2739}, + {DSI_WR_DATA, 0x2739}, // MIPI_DSI_DCS_LONG_WRITE: 39 bytes. {DSI_WR_DATA, 0xFFFFFFD8}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, @@ -222,25 +214,25 @@ static const cfg_op_t _display_config_4[43] = { {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2BD15}, + {DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x2BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xF39}, + {DSI_WR_DATA, 0xF39}, // MIPI_DSI_DCS_LONG_WRITE: 15 bytes. {DSI_WR_DATA, 0xFFFFFFD8}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x6D915}, + {DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x6D9. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; -//DSI config. -static const cfg_op_t _display_config_5[21] = { +//DSI packet config. +static const cfg_op_t _display_dsi_packet_config[21] = { {DSI_PAD_CONTROL_1, 0}, {DSI_PHY_TIMING_0, 0x6070601}, {DSI_PHY_TIMING_1, 0x40A0E05}, @@ -264,15 +256,8 @@ static const cfg_op_t _display_config_5[21] = { {DSI_HOST_CONTROL, 0}, }; -//Clock config. -static const cfg_op_t _display_config_6[3] = { - {0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//DSI config. -static const cfg_op_t _display_config_7[10] = { +//DSI mode config. +static const cfg_op_t _display_dsi_mode_config[10] = { {DSI_TRIGGER, 0}, {DSI_CONTROL, 0}, {DSI_SOL_DELAY, 6}, @@ -286,17 +271,17 @@ static const cfg_op_t _display_config_7[10] = { }; //MIPI CAL config. -static const cfg_op_t _display_config_8[6] = { - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS - {0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0 - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1 +static const cfg_op_t _display_mipi_pad_cal_config[6] = { + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, + {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300} }; //DSI config. -static const cfg_op_t _display_config_9[4] = { +static const cfg_op_t _display_dsi_pad_cal_config[4] = { {DSI_PAD_CONTROL_1, 0}, {DSI_PAD_CONTROL_2, 0}, {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, @@ -304,27 +289,27 @@ static const cfg_op_t _display_config_9[4] = { }; //MIPI CAL config. -static const cfg_op_t _display_config_10[16] = { - {0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG - {0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG - {0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 - {0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG - {0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG - {0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG - {0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG - {0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG - {0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG - {0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG - {0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG - {0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 - {0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 - {0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG +static const cfg_op_t _display_mipi_apply_dsi_cal_config[16] = { + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001} }; //Display A config. -static const cfg_op_t _display_config_11[113] = { +static const cfg_op_t _display_video_disp_controller_enable_config[113] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, @@ -449,7 +434,7 @@ static const cfg_op_t _display_config_11[113] = { }; ////Display A config. -static const cfg_op_t _display_config_12[17] = { +static const cfg_op_t _display_video_disp_controller_disable_config[17] = { {DC_DISP_FRONT_PORCH, 0xA0088}, {DC_CMD_INT_MASK, 0}, {DC_CMD_STATE_ACCESS, 0}, @@ -470,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = { }; //DSI config. -static const cfg_op_t _display_config_13[16] = { +static const cfg_op_t _display_dsi_timing_deinit_config[16] = { {DSI_POWER_CONTROL, 0}, {DSI_PAD_CONTROL_1, 0}, {DSI_PHY_TIMING_0, 0x6070601}, @@ -490,11 +475,11 @@ static const cfg_op_t _display_config_13[16] = { }; //DSI config (if ver == 0x10). -static const cfg_op_t _display_config_14[22] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, +static const cfg_op_t _display_deinit_config_jdi[22] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2139}, + {DSI_WR_DATA, 0x2139}, // MIPI_DSI_DCS_LONG_WRITE: 33 bytes. {DSI_WR_DATA, 0x191919D5}, {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, @@ -505,60 +490,107 @@ static const cfg_op_t _display_config_14[22] = { {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xB39}, - {DSI_WR_DATA, 0x4F0F41B1}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x4F0F41B1}, // Set Power control. {DSI_WR_DATA, 0xF179A433}, - {DSI_WR_DATA, 0x2D81}, + {DSI_WR_DATA, 0x002D81}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; +static const cfg_op_t _display_deinit_config_auo[37] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D5}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D6}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x711148B1}, // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + {DSI_WR_DATA, 0x71143209}, + {DSI_WR_DATA, 0x114D31}, // Set Power control. (Unknown). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. + {DSI_TRIGGER, DSI_TRIGGER_HOST} +}; + +static const cfg_op_t _display_init_config_invert[3] = { + {DSI_WR_DATA, 0x239}, + {DSI_WR_DATA, 0x02C1}, // INV_EN. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, +}; + //Display A config. static const cfg_op_t cfg_display_one_color[8] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display. + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display. }; //Display A config. static const cfg_op_t cfg_display_framebuffer[32] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_POSITION, 0}, //(0,0) {DC_WIN_H_INITIAL_DDA, 0}, {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, - {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. - {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. - {DC_WIN_BUFFER_CONTROL, 0}, - {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. {DC_WINBUF_ADDR_H_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD. - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} }; diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 4323e49..e4abe4e 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it @@ -20,6 +20,10 @@ #include #include "gfx.h" +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index 94cb0ed..0871820 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2019 CTCaer - * Copyright (C) 2018 M4xw + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -49,7 +49,7 @@ void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 po void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); // Global gfx console and context. -gfx_ctxt_t gfx_ctxt; -gfx_con_t gfx_con; +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; #endif diff --git a/source/gfx/tui.h b/source/gfx/tui.h index 2b7d3f7..a503b08 100644 --- a/source/gfx/tui.h +++ b/source/gfx/tui.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (C) 2018 CTCaer +* Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/hos/fss.c b/source/hos/fss.c new file mode 100644 index 0000000..8e255ea --- /dev/null +++ b/source/hos/fss.c @@ -0,0 +1,247 @@ +/* + * Atmosphère Fusée Secondary Storage parser. + * + * 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 . + */ + +#include + +#include "fss.h" +// #include "hos.h" +#include "../config/config.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../storage/emummc.h" +#include "../storage/nx_sd.h" + +#include "../gfx/gfx.h" +#define DPRINTF(...) + +extern hekate_config h_cfg; + +extern bool is_ipl_updated(void *buf, char *path, bool force); + +// FSS0 Magic and Meta header offset. +#define FSS0_MAGIC 0x30535346 +#define FSS0_META_OFFSET 0x4 + +// FSS0 Content Types. +#define CNT_TYPE_FSP 0 +#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor). +#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw). +#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw). +#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader). +#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys). +#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition). +#define CNT_TYPE_BMP 7 +#define CNT_TYPE_EMC 8 +#define CNT_TYPE_KLD 9 // Kernel Loader. +#define CNT_TYPE_KRN 10 // Kernel. + +// FSS0 Content Flags. +#define CNT_FLAG0_EXPERIMENTAL (1 << 0) + +// FSS0 Meta Header. +typedef struct _fss_meta_t +{ + u32 magic; + u32 size; + u32 crt0_off; + u32 cnt_off; + u32 cnt_count; + u32 hos_ver; + u32 version; + u32 git_rev; +} fss_meta_t; + +// FSS0 Content Header. +typedef struct _fss_content_t +{ + u32 offset; + u32 size; + u8 type; + u8 flags0; + u8 flags1; + u8 flags2; + u32 rsvd1; + char name[0x10]; +} fss_content_t; + +static void _update_r2p(const char *path) +{ + char *r2p_path = malloc(256); + u32 path_len = strlen(path); + strcpy(r2p_path, path); + + while(path_len) + { + if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C)) + { + r2p_path[path_len] = 0; + strcat(r2p_path, "reboot_payload.bin"); + u8 *r2p_payload = sd_file_read(r2p_path, NULL); + + is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false); + + free(r2p_payload); + break; + } + path_len--; + } + + free(r2p_path); +} + +int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) +{ + FIL fp; + + bool stock = false; + int sept_used = 0; + + if (!sept_ctxt) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) + { + if (!strcmp("stock", kv->key)) + if (kv->val[0] == '1') + stock = true; + } + + if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable)) + return 1; + } + + if (f_open(&fp, path, FA_READ) != FR_OK) + return 0; + + void *fss = malloc(f_size(&fp)); + + // Read first 1024 bytes of the fss file. + f_read(&fp, fss, 1024, NULL); + + // Get FSS0 Meta header offset. + u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET); + fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr); + + // Check if valid FSS0 and parse it. + if (fss_meta->magic == FSS0_MAGIC) + { + gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" + "Max HOS supported: %d.%d.%d\n" + "Unpacking and loading components.. ", + fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, + fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); + + if (!sept_ctxt) + { + ctxt->atmosphere = true; + ctxt->fss0_hosver = fss_meta->hos_ver; + } + + // Parse FSS0 contents. + fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off); + void *content; + for (u32 i = 0; i < fss_meta->cnt_count; i++) + { + content = (void *)(fss + curr_fss_cnt[i].offset); + + // Check if offset is inside limits. + if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size) + continue; + + // If content is experimental and experimental flag is not enabled, skip it. + if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental) + continue; + + // Parse content. + if (!sept_ctxt) + { + // Prepare content context. + switch (curr_fss_cnt[i].type) + { + case CNT_TYPE_KIP: + if (stock) + continue; + merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); + mkip1->kip1 = content; + list_append(&ctxt->kip1_list, &mkip1->link); + DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); + break; + case CNT_TYPE_EXO: + ctxt->secmon_size = curr_fss_cnt[i].size; + ctxt->secmon = content; + break; + case CNT_TYPE_WBT: + ctxt->warmboot_size = curr_fss_cnt[i].size; + ctxt->warmboot = content; + break; + default: + continue; + } + + // Load content to launch context. + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, content, curr_fss_cnt[i].size, NULL); + } + else + { + // Load sept content directly to launch context. + switch (curr_fss_cnt[i].type) + { + case CNT_TYPE_SP1: + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL); + break; + case CNT_TYPE_SP2: + if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15)) + { + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL); + sept_used = 1; + goto out; + } + break; + default: + break; + } + } + } + +out: + gfx_printf("Done!\n"); + f_close(&fp); + + _update_r2p(path); + + return (!sept_ctxt ? 1 : sept_used); + } + + f_close(&fp); + free(fss); + + return 0; +} + +int load_sept_from_ffs0(fss0_sept_t *sept_ctxt) +{ + LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link) + { + if (!strcmp("fss0", kv->key)) + return parse_fss(NULL, kv->val, sept_ctxt); + } + + return 0; +} diff --git a/source/hos/fss.h b/source/hos/fss.h new file mode 100644 index 0000000..3f56d7c --- /dev/null +++ b/source/hos/fss.h @@ -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 . + */ + +#ifndef _FSS_H_ +#define _FSS_H_ + +#include "hos.h" + +typedef struct _fss0_sept_t +{ + u32 kb; + ini_sec_t *cfg_sec; + void *sept_primary; + void *sept_secondary; + +} fss0_sept_t; + +int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt); +int load_sept_from_ffs0(fss0_sept_t *sept_ctxt); + +#endif diff --git a/source/hos/hos.h b/source/hos/hos.h new file mode 100644 index 0000000..d2c8712 --- /dev/null +++ b/source/hos/hos.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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 . + */ + +#ifndef _HOS_H_ +#define _HOS_H_ + +#include "pkg1.h" +#include "pkg2.h" +#include "../utils/types.h" +#include "../config/ini.h" +#include "../sec/tsec.h" + +#include + +#define KB_FIRMWARE_VERSION_100_200 0 +#define KB_FIRMWARE_VERSION_300 1 +#define KB_FIRMWARE_VERSION_301 2 +#define KB_FIRMWARE_VERSION_400 3 +#define KB_FIRMWARE_VERSION_500 4 +#define KB_FIRMWARE_VERSION_600 5 +#define KB_FIRMWARE_VERSION_620 6 +#define KB_FIRMWARE_VERSION_700 7 +#define KB_FIRMWARE_VERSION_810 8 +#define KB_FIRMWARE_VERSION_900 9 +#define KB_FIRMWARE_VERSION_910 10 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 + +#define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x30534B45 + +typedef struct _exo_ctxt_t +{ + bool no_user_exceptions; + bool user_pmu; + bool *cal0_blank; + bool *cal0_allow_writes_sys; +} exo_ctxt_t; + +typedef struct _hos_eks_keys_t +{ + u8 dkg[0x10]; + u8 mkk[0x10]; + u8 fdk[0x10]; + u8 dkk[0x10]; +} hos_eks_keys_t; + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u32 enabled; + u32 sbk_low[2]; + hos_eks_keys_t keys[6]; + u32 magic2; + u32 rsvd2[3]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) == 416, "HOS EKS storage bigger than MBR!"); + +typedef struct _launch_ctxt_t +{ + void *keyblob; + + void *pkg1; + const pkg1_id_t *pkg1_id; + const pkg2_kernel_id_t *pkg2_kernel_id; + + void *warmboot; + u32 warmboot_size; + void *secmon; + u32 secmon_size; + + void *pkg2; + u32 pkg2_size; + bool new_pkg2; + + void *kernel; + u32 kernel_size; + link_t kip1_list; + char* kip1_patches; + + u32 fss0_hosver; + bool svcperm; + bool debugmode; + bool stock; + bool atmosphere; + bool fss0_enable_experimental; + bool emummc_forced; + + exo_ctxt_t exo_cfg; + + ini_sec_t *cfg; +} launch_ctxt_t; + +typedef struct _merge_kip_t +{ + void *kip1; + link_t link; +} merge_kip_t; + +void hos_eks_get(); +void hos_eks_save(u32 kb); +void hos_eks_clear(u32 kb); +int hos_launch(ini_sec_t *cfg); +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); + +#endif diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index bc77d1e..09ebb67 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -26,6 +26,10 @@ #include "../gfx/gfx.h" +u32 pkg2_newkern_ini1_val; +u32 pkg2_newkern_ini1_start; +u32 pkg2_newkern_ini1_end; + /*#include "util.h" #define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DEBUG_PRINTING*/ diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index ba6a8a0..96e8fe5 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2020 CTCaer + * Copyright (c) 2018-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, @@ -28,9 +28,17 @@ #define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset. -u32 pkg2_newkern_ini1_val; -u32 pkg2_newkern_ini1_start; -u32 pkg2_newkern_ini1_end; +extern u32 pkg2_newkern_ini1_val; +extern u32 pkg2_newkern_ini1_start; +extern u32 pkg2_newkern_ini1_end; + +typedef struct _kernel_patch_t +{ + u32 id; + u32 off; + u32 val; + u32 *ptr; +} kernel_patch_t; typedef struct _pkg2_hdr_t { @@ -87,6 +95,12 @@ typedef struct _pkg2_kip1_info_t link_t link; } pkg2_kip1_info_t; +typedef struct _pkg2_kernel_id_t +{ + u8 hash[8]; + kernel_patch_t *kernel_patchset; +} pkg2_kernel_id_t; + 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); pkg2_hdr_t *pkg2_decrypt(void *data); diff --git a/source/hos/sept.c b/source/hos/sept.c index 2a30f16..4d4c6fa 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -18,12 +18,14 @@ #include "sept.h" #include "../gfx/di.h" +#include "../hos/hos.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" #include "../soc/hw_init.h" #include "../soc/pmc.h" #include "../soc/t210.h" #include "../storage/nx_emmc.h" +#include "../storage/nx_sd.h" #include "../storage/sdmmc.h" #include "../utils/btn.h" #include "../utils/types.h" @@ -58,7 +60,6 @@ u8 warmboot_reboot[] = { extern u32 color_idx; extern boot_cfg_t b_cfg; -extern void sd_unmount(); extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) diff --git a/source/ianos/ianos.c b/source/ianos/ianos.c index 18d4165..85ac9c9 100644 --- a/source/ianos/ianos.c +++ b/source/ianos/ianos.c @@ -18,21 +18,18 @@ #include #include "ianos.h" -#include "../utils/types.h" -#include "../libs/elfload/elfload.h" #include "../../common/common_module.h" -#include "../mem/heap.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 DRAM_LIB_ADDR 0xE0000000 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 *fileBuf = NULL; diff --git a/source/keys/keys.c b/source/keys/keys.c index f54915b..5097a10 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -20,6 +20,7 @@ #include "../gfx/di.h" #include "../gfx/gfx.h" #include "../gfx/tui.h" +#include "../hos/hos.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/sept.h" @@ -36,6 +37,7 @@ #include "../soc/t210.h" #include "../storage/emummc.h" #include "../storage/nx_emmc.h" +#include "../storage/nx_sd.h" #include "../storage/sdmmc.h" #include "../utils/btn.h" #include "../utils/list.h" @@ -47,10 +49,6 @@ #include -extern bool sd_mount(); -extern void sd_unmount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); - extern hekate_config h_cfg; extern bool clear_sector_cache; @@ -149,7 +147,7 @@ void dump_keys() { tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; - if (!emummc_storage_init_mmc(&storage, &sdmmc)) { + if (emummc_storage_init_mmc(&storage, &sdmmc)) { EPRINTF("Unable to init MMC."); goto out_wait; } @@ -157,7 +155,7 @@ void dump_keys() { // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); - emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { @@ -220,11 +218,13 @@ void dump_keys() { EPRINTF("Unable to open /sept/payload.bin to write."); goto out_wait; } + gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { EPRINTF("Unable to write self to /sept/payload.bin."); f_close(&fp); goto out_wait; } + gfx_printf(" done"); f_close(&fp); gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); @@ -388,7 +388,7 @@ get_tsec: ; u8 *pkg2 = NULL; pkg2_kip1_info_t *ki = NULL; - emummc_storage_set_mmc_partition(&storage, 0); + emummc_storage_set_mmc_partition(&storage, EMMC_GPP); // Parse eMMC GPT. LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &storage); diff --git a/source/keys/save.c b/source/keys/save.c index 763c45b..8e11c9a 100644 --- a/source/keys/save.c +++ b/source/keys/save.c @@ -351,7 +351,7 @@ void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, ctx->physical_block = initial_block; ctx->virtual_block = 0; - allocation_table_entry_t entry; + allocation_table_entry_t entry = {0, 0}; entry.next = initial_block; ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); ctx->next_block = entry.next; @@ -369,7 +369,7 @@ int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ct ctx->virtual_block += ctx->current_segment_size; ctx->physical_block = ctx->next_block; - allocation_table_entry_t entry; + allocation_table_entry_t entry = {0, 0}; entry.next = ctx->next_block; ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); ctx->next_block = entry.next; @@ -383,7 +383,7 @@ int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ct ctx->physical_block = ctx->prev_block; - allocation_table_entry_t entry; + allocation_table_entry_t entry = {0, 0}; entry.next = ctx->prev_block; ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); ctx->next_block = entry.next; diff --git a/source/libs/compr/blz.c b/source/libs/compr/blz.c index 226d011..685ef4a 100644 --- a/source/libs/compr/blz.c +++ b/source/libs/compr/blz.c @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include "blz.h" diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index cd8bef0..ebd7f22 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -43,7 +43,7 @@ #define FF_FASTFS 0 -#ifdef FF_FASTFS +#if FF_FASTFS #define FF_USE_FASTSEEK 1 #else #define FF_USE_FASTSEEK 0 diff --git a/source/main.c b/source/main.c index 5ad772d..855a4af 100644 --- a/source/main.c +++ b/source/main.c @@ -33,6 +33,7 @@ #include "soc/hw_init.h" #include "storage/emummc.h" #include "storage/nx_emmc.h" +#include "storage/nx_sd.h" #include "storage/sdmmc.h" #include "utils/btn.h" #include "utils/dirlist.h" @@ -41,95 +42,11 @@ #include "keys/keys.h" -sdmmc_t sd_sdmmc; -sdmmc_storage_t sd_storage; -__attribute__ ((aligned (16))) FATFS sd_fs; -static bool sd_mounted; - hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; -bool sd_mount() -{ - if (sd_mounted) - return true; - - if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) - { - EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); - } - else - { - int res = 0; - res = f_mount(&sd_fs, "sd:", 1); - if (res == FR_OK) - { - sd_mounted = 1; - return true; - } - else - { - EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); - } - } - - return false; -} - -void sd_unmount() -{ - if (sd_mounted) - { - f_mount(NULL, "sd:", 1); - sdmmc_storage_end(&sd_storage); - sd_mounted = 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; -} - // This is a safe and unused DRAM region for our payloads. #define RELOC_META_OFF 0x7C #define PATCHED_RELOC_SZ 0x94 @@ -376,9 +293,9 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) { sdmmc_t sdmmc; sdmmc_storage_t storage; - 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); u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0); sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); sdmmc_storage_end(&storage); @@ -394,7 +311,7 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) emummc_storage_init_mmc(&storage, &sdmmc); memset(pkg1, 0, NX_EMMC_BLOCKSIZE); - emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); pkg1_id = pkg1_identify(pkg1); emummc_storage_end(&storage); diff --git a/source/mem/emc.h b/source/mem/emc.h index 88e9da9..9be6fe8 100644 --- a/source/mem/emc.h +++ b/source/mem/emc.h @@ -2,6 +2,7 @@ * arch/arm/mach-tegra/tegra21_emc.h * * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2020, CTCaer. * * 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 @@ -22,117 +23,117 @@ #ifndef _EMC_H_ #define _EMC_H_ -#define EMC_DBG 0x8 -#define EMC_CFG 0xC -#define EMC_CONFIG_SAMPLE_DELAY 0x5f0 -#define EMC_CFG_UPDATE 0x5f4 -#define EMC_ADR_CFG 0x10 -#define EMC_REFCTRL 0x20 -#define EMC_PIN 0x24 -#define EMC_TIMING_CONTROL 0x28 -#define EMC_RC 0x2c -#define EMC_RFC 0x30 -#define EMC_RFCPB 0x590 -#define EMC_RAS 0x34 -#define EMC_RP 0x38 -#define EMC_R2W 0x3c -#define EMC_W2R 0x40 -#define EMC_R2P 0x44 -#define EMC_W2P 0x48 -#define EMC_CCDMW 0x5c0 -#define EMC_RD_RCD 0x4c -#define EMC_WR_RCD 0x50 -#define EMC_RRD 0x54 -#define EMC_REXT 0x58 -#define EMC_WDV 0x5c -#define EMC_QUSE 0x60 -#define EMC_QRST 0x64 -#define EMC_ISSUE_QRST 0x428 -#define EMC_QSAFE 0x68 -#define EMC_RDV 0x6c -#define EMC_REFRESH 0x70 -#define EMC_BURST_REFRESH_NUM 0x74 -#define EMC_PDEX2WR 0x78 -#define EMC_PDEX2RD 0x7c -#define EMC_PDEX2CKE 0x118 -#define EMC_PCHG2PDEN 0x80 -#define EMC_ACT2PDEN 0x84 -#define EMC_AR2PDEN 0x88 -#define EMC_RW2PDEN 0x8c -#define EMC_CKE2PDEN 0x11c -#define EMC_TXSR 0x90 -#define EMC_TCKE 0x94 -#define EMC_TFAW 0x98 -#define EMC_TRPAB 0x9c -#define EMC_TCLKSTABLE 0xa0 -#define EMC_TCLKSTOP 0xa4 -#define EMC_TREFBW 0xa8 -#define EMC_TPPD 0xac -#define EMC_PDEX2MRR 0xb4 -#define EMC_ODT_WRITE 0xb0 -#define EMC_WEXT 0xb8 -#define EMC_RFC_SLR 0xc0 -#define EMC_MRS_WAIT_CNT2 0xc4 -#define EMC_MRS_WAIT_CNT 0xc8 -#define EMC_MRS 0xcc -#define EMC_EMRS 0xd0 -#define EMC_REF 0xd4 -#define EMC_PRE 0xd8 -#define EMC_NOP 0xdc -#define EMC_SELF_REF 0xe0 -#define EMC_DPD 0xe4 -#define EMC_MRW 0xe8 -#define EMC_MRR 0xec -#define EMC_CMDQ 0xf0 -#define EMC_MC2EMCQ 0xf4 -#define EMC_FBIO_SPARE 0x100 -#define EMC_FBIO_CFG5 0x104 -#define EMC_CFG_RSV 0x120 -#define EMC_ACPD_CONTROL 0x124 -#define EMC_MPC 0x128 -#define EMC_EMRS2 0x12c -#define EMC_EMRS3 0x130 -#define EMC_MRW2 0x134 -#define EMC_MRW3 0x138 -#define EMC_MRW4 0x13c -#define EMC_MRW5 0x4a0 -#define EMC_MRW6 0x4a4 -#define EMC_MRW7 0x4a8 -#define EMC_MRW8 0x4ac -#define EMC_MRW9 0x4b0 -#define EMC_MRW10 0x4b4 -#define EMC_MRW11 0x4b8 -#define EMC_MRW12 0x4bc -#define EMC_MRW13 0x4c0 -#define EMC_MRW14 0x4c4 -#define EMC_MRW15 0x4d0 -#define EMC_CFG_SYNC 0x4d4 -#define EMC_CLKEN_OVERRIDE 0x140 -#define EMC_R2R 0x144 -#define EMC_W2W 0x148 -#define EMC_EINPUT 0x14c -#define EMC_EINPUT_DURATION 0x150 -#define EMC_PUTERM_EXTRA 0x154 -#define EMC_TCKESR 0x158 -#define EMC_TPD 0x15c -#define EMC_STAT_CONTROL 0x160 -#define EMC_STAT_STATUS 0x164 -#define EMC_STAT_DRAM_CLOCK_LIMIT_LO 0x19c -#define EMC_STAT_DRAM_CLOCK_LIMIT_HI 0x1a0 -#define EMC_STAT_DRAM_CLOCKS_LO 0x1a4 -#define EMC_STAT_DRAM_CLOCKS_HI 0x1a8 -#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 0x1ac -#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 0x1b0 -#define EMC_STAT_DRAM_DEV0_READ_CNT_LO 0x1b4 -#define EMC_STAT_DRAM_DEV0_READ_CNT_HI 0x1b8 -#define EMC_STAT_DRAM_DEV0_READ8_CNT_LO 0x1bc -#define EMC_STAT_DRAM_DEV0_READ8_CNT_HI 0x1c0 -#define EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 0x1c4 -#define EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 0x1c8 -#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 0x1cc -#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 0x1d0 -#define EMC_STAT_DRAM_DEV0_REF_CNT_LO 0x1d4 -#define EMC_STAT_DRAM_DEV0_REF_CNT_HI 0x1d8 +#define EMC_DBG 0x8 +#define EMC_CFG 0xC +#define EMC_CONFIG_SAMPLE_DELAY 0x5f0 +#define EMC_CFG_UPDATE 0x5f4 +#define EMC_ADR_CFG 0x10 +#define EMC_REFCTRL 0x20 +#define EMC_PIN 0x24 +#define EMC_TIMING_CONTROL 0x28 +#define EMC_RC 0x2c +#define EMC_RFC 0x30 +#define EMC_RFCPB 0x590 +#define EMC_RAS 0x34 +#define EMC_RP 0x38 +#define EMC_R2W 0x3c +#define EMC_W2R 0x40 +#define EMC_R2P 0x44 +#define EMC_W2P 0x48 +#define EMC_CCDMW 0x5c0 +#define EMC_RD_RCD 0x4c +#define EMC_WR_RCD 0x50 +#define EMC_RRD 0x54 +#define EMC_REXT 0x58 +#define EMC_WDV 0x5c +#define EMC_QUSE 0x60 +#define EMC_QRST 0x64 +#define EMC_ISSUE_QRST 0x428 +#define EMC_QSAFE 0x68 +#define EMC_RDV 0x6c +#define EMC_REFRESH 0x70 +#define EMC_BURST_REFRESH_NUM 0x74 +#define EMC_PDEX2WR 0x78 +#define EMC_PDEX2RD 0x7c +#define EMC_PDEX2CKE 0x118 +#define EMC_PCHG2PDEN 0x80 +#define EMC_ACT2PDEN 0x84 +#define EMC_AR2PDEN 0x88 +#define EMC_RW2PDEN 0x8c +#define EMC_CKE2PDEN 0x11c +#define EMC_TXSR 0x90 +#define EMC_TCKE 0x94 +#define EMC_TFAW 0x98 +#define EMC_TRPAB 0x9c +#define EMC_TCLKSTABLE 0xa0 +#define EMC_TCLKSTOP 0xa4 +#define EMC_TREFBW 0xa8 +#define EMC_TPPD 0xac +#define EMC_PDEX2MRR 0xb4 +#define EMC_ODT_WRITE 0xb0 +#define EMC_WEXT 0xb8 +#define EMC_RFC_SLR 0xc0 +#define EMC_MRS_WAIT_CNT2 0xc4 +#define EMC_MRS_WAIT_CNT 0xc8 +#define EMC_MRS 0xcc +#define EMC_EMRS 0xd0 +#define EMC_REF 0xd4 +#define EMC_PRE 0xd8 +#define EMC_NOP 0xdc +#define EMC_SELF_REF 0xe0 +#define EMC_DPD 0xe4 +#define EMC_MRW 0xe8 +#define EMC_MRR 0xec +#define EMC_CMDQ 0xf0 +#define EMC_MC2EMCQ 0xf4 +#define EMC_FBIO_SPARE 0x100 +#define EMC_FBIO_CFG5 0x104 +#define EMC_CFG_RSV 0x120 +#define EMC_ACPD_CONTROL 0x124 +#define EMC_MPC 0x128 +#define EMC_EMRS2 0x12c +#define EMC_EMRS3 0x130 +#define EMC_MRW2 0x134 +#define EMC_MRW3 0x138 +#define EMC_MRW4 0x13c +#define EMC_MRW5 0x4a0 +#define EMC_MRW6 0x4a4 +#define EMC_MRW7 0x4a8 +#define EMC_MRW8 0x4ac +#define EMC_MRW9 0x4b0 +#define EMC_MRW10 0x4b4 +#define EMC_MRW11 0x4b8 +#define EMC_MRW12 0x4bc +#define EMC_MRW13 0x4c0 +#define EMC_MRW14 0x4c4 +#define EMC_MRW15 0x4d0 +#define EMC_CFG_SYNC 0x4d4 +#define EMC_CLKEN_OVERRIDE 0x140 +#define EMC_R2R 0x144 +#define EMC_W2W 0x148 +#define EMC_EINPUT 0x14c +#define EMC_EINPUT_DURATION 0x150 +#define EMC_PUTERM_EXTRA 0x154 +#define EMC_TCKESR 0x158 +#define EMC_TPD 0x15c +#define EMC_STAT_CONTROL 0x160 +#define EMC_STAT_STATUS 0x164 +#define EMC_STAT_DRAM_CLOCK_LIMIT_LO 0x19c +#define EMC_STAT_DRAM_CLOCK_LIMIT_HI 0x1a0 +#define EMC_STAT_DRAM_CLOCKS_LO 0x1a4 +#define EMC_STAT_DRAM_CLOCKS_HI 0x1a8 +#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 0x1ac +#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 0x1b0 +#define EMC_STAT_DRAM_DEV0_READ_CNT_LO 0x1b4 +#define EMC_STAT_DRAM_DEV0_READ_CNT_HI 0x1b8 +#define EMC_STAT_DRAM_DEV0_READ8_CNT_LO 0x1bc +#define EMC_STAT_DRAM_DEV0_READ8_CNT_HI 0x1c0 +#define EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 0x1c4 +#define EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 0x1c8 +#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 0x1cc +#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 0x1d0 +#define EMC_STAT_DRAM_DEV0_REF_CNT_LO 0x1d4 +#define EMC_STAT_DRAM_DEV0_REF_CNT_HI 0x1d8 #define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1dc #define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x1e0 #define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1e4 @@ -149,21 +150,21 @@ #define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x210 #define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x214 #define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x218 -#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 0x21c -#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 0x220 -#define EMC_STAT_DRAM_DEV0_DSR 0x224 -#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 0x228 -#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 0x22c -#define EMC_STAT_DRAM_DEV1_READ_CNT_LO 0x230 -#define EMC_STAT_DRAM_DEV1_READ_CNT_HI 0x234 -#define EMC_STAT_DRAM_DEV1_READ8_CNT_LO 0x238 -#define EMC_STAT_DRAM_DEV1_READ8_CNT_HI 0x23c -#define EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 0x240 -#define EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 0x244 -#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 0x248 -#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 0x24c -#define EMC_STAT_DRAM_DEV1_REF_CNT_LO 0x250 -#define EMC_STAT_DRAM_DEV1_REF_CNT_HI 0x254 +#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 0x21c +#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 0x220 +#define EMC_STAT_DRAM_DEV0_DSR 0x224 +#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 0x228 +#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 0x22c +#define EMC_STAT_DRAM_DEV1_READ_CNT_LO 0x230 +#define EMC_STAT_DRAM_DEV1_READ_CNT_HI 0x234 +#define EMC_STAT_DRAM_DEV1_READ8_CNT_LO 0x238 +#define EMC_STAT_DRAM_DEV1_READ8_CNT_HI 0x23c +#define EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 0x240 +#define EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 0x244 +#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 0x248 +#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 0x24c +#define EMC_STAT_DRAM_DEV1_REF_CNT_LO 0x250 +#define EMC_STAT_DRAM_DEV1_REF_CNT_HI 0x254 #define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x258 #define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x25c #define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x260 @@ -180,9 +181,9 @@ #define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x28c #define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x290 #define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x294 -#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 0x298 -#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 0x29c -#define EMC_STAT_DRAM_DEV1_DSR 0x2a0 +#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 0x298 +#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 0x29c +#define EMC_STAT_DRAM_DEV1_DSR 0x2a0 #define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc8c #define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0xc90 #define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc94 @@ -199,469 +200,494 @@ #define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc0 #define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0xcc4 #define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc8 -#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO 0xccc -#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI 0xcd0 -#define EMC_STAT_DRAM_IO_DSR 0xcd4 -#define EMC_AUTO_CAL_CONFIG 0x2a4 -#define EMC_AUTO_CAL_CONFIG2 0x458 -#define EMC_AUTO_CAL_CONFIG3 0x45c -#define EMC_AUTO_CAL_CONFIG4 0x5b0 -#define EMC_AUTO_CAL_CONFIG5 0x5b4 -#define EMC_AUTO_CAL_CONFIG6 0x5cc -#define EMC_AUTO_CAL_CONFIG7 0x574 -#define EMC_AUTO_CAL_CONFIG8 0x2dc -#define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 -#define EMC_AUTO_CAL_VREF_SEL_1 0x300 -#define EMC_AUTO_CAL_INTERVAL 0x2a8 -#define EMC_AUTO_CAL_STATUS 0x2ac -#define EMC_AUTO_CAL_STATUS2 0x3d4 -#define EMC_AUTO_CAL_CHANNEL 0x464 -#define EMC_PMACRO_RX_TERM 0xc48 -#define EMC_PMACRO_DQ_TX_DRV 0xc70 -#define EMC_PMACRO_CA_TX_DRV 0xc74 -#define EMC_PMACRO_CMD_TX_DRV 0xc4c -#define EMC_PMACRO_AUTOCAL_CFG_0 0x700 -#define EMC_PMACRO_AUTOCAL_CFG_1 0x704 -#define EMC_PMACRO_AUTOCAL_CFG_2 0x708 -#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xc78 -#define EMC_PMACRO_ZCTRL 0xc44 -#define EMC_XM2COMPPADCTRL 0x30c -#define EMC_XM2COMPPADCTRL2 0x578 -#define EMC_XM2COMPPADCTRL3 0x2f4 -#define EMC_COMP_PAD_SW_CTRL 0x57c -#define EMC_REQ_CTRL 0x2b0 -#define EMC_EMC_STATUS 0x2b4 -#define EMC_CFG_2 0x2b8 -#define EMC_CFG_DIG_DLL 0x2bc -#define EMC_CFG_DIG_DLL_PERIOD 0x2c0 -#define EMC_DIG_DLL_STATUS 0x2c4 -#define EMC_CFG_DIG_DLL_1 0x2c8 -#define EMC_RDV_MASK 0x2cc -#define EMC_WDV_MASK 0x2d0 -#define EMC_RDV_EARLY_MASK 0x2d4 -#define EMC_RDV_EARLY 0x2d8 -#define EMC_WDV_CHK 0x4e0 -#define EMC_ZCAL_INTERVAL 0x2e0 -#define EMC_ZCAL_WAIT_CNT 0x2e4 -#define EMC_ZCAL_MRW_CMD 0x2e8 -#define EMC_ZQ_CAL 0x2ec -#define EMC_SCRATCH0 0x324 -#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 0x3c8 -#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3cc -#define EMC_UNSTALL_RW_AFTER_CLKCHANGE 0x3d0 -#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4d8 -#define EMC_SEL_DPD_CTRL 0x3d8 -#define EMC_FDPD_CTRL_DQ 0x310 -#define EMC_FDPD_CTRL_CMD 0x314 -#define EMC_PRE_REFRESH_REQ_CNT 0x3dc -#define EMC_REFCTRL2 0x580 -#define EMC_FBIO_CFG7 0x584 -#define EMC_DATA_BRLSHFT_0 0x588 -#define EMC_DATA_BRLSHFT_1 0x58c -#define EMC_DQS_BRLSHFT_0 0x594 -#define EMC_DQS_BRLSHFT_1 0x598 -#define EMC_CMD_BRLSHFT_0 0x59c -#define EMC_CMD_BRLSHFT_1 0x5a0 -#define EMC_CMD_BRLSHFT_2 0x5a4 -#define EMC_CMD_BRLSHFT_3 0x5a8 -#define EMC_QUSE_BRLSHFT_0 0x5ac -#define EMC_QUSE_BRLSHFT_1 0x5b8 -#define EMC_QUSE_BRLSHFT_2 0x5bc -#define EMC_QUSE_BRLSHFT_3 0x5c4 -#define EMC_FBIO_CFG8 0x5c8 -#define EMC_CMD_MAPPING_CMD0_0 0x380 -#define EMC_CMD_MAPPING_CMD0_1 0x384 -#define EMC_CMD_MAPPING_CMD0_2 0x388 -#define EMC_CMD_MAPPING_CMD1_0 0x38c -#define EMC_CMD_MAPPING_CMD1_1 0x390 -#define EMC_CMD_MAPPING_CMD1_2 0x394 -#define EMC_CMD_MAPPING_CMD2_0 0x398 -#define EMC_CMD_MAPPING_CMD2_1 0x39c -#define EMC_CMD_MAPPING_CMD2_2 0x3a0 -#define EMC_CMD_MAPPING_CMD3_0 0x3a4 -#define EMC_CMD_MAPPING_CMD3_1 0x3a8 -#define EMC_CMD_MAPPING_CMD3_2 0x3ac -#define EMC_CMD_MAPPING_BYTE 0x3b0 -#define EMC_DYN_SELF_REF_CONTROL 0x3e0 -#define EMC_TXSRDLL 0x3e4 -#define EMC_CCFIFO_ADDR 0x3e8 -#define EMC_CCFIFO_DATA 0x3ec -#define EMC_CCFIFO_STATUS 0x3f0 -#define EMC_SWIZZLE_RANK0_BYTE0 0x404 -#define EMC_SWIZZLE_RANK0_BYTE1 0x408 -#define EMC_SWIZZLE_RANK0_BYTE2 0x40c -#define EMC_SWIZZLE_RANK0_BYTE3 0x410 -#define EMC_SWIZZLE_RANK1_BYTE0 0x418 -#define EMC_SWIZZLE_RANK1_BYTE1 0x41c -#define EMC_SWIZZLE_RANK1_BYTE2 0x420 -#define EMC_SWIZZLE_RANK1_BYTE3 0x424 -#define EMC_TR_TIMING_0 0x3b4 -#define EMC_TR_CTRL_0 0x3b8 -#define EMC_TR_CTRL_1 0x3bc -#define EMC_TR_DVFS 0x460 -#define EMC_SWITCH_BACK_CTRL 0x3c0 -#define EMC_TR_RDV 0x3c4 -#define EMC_TR_QPOP 0x3f4 -#define EMC_TR_RDV_MASK 0x3f8 -#define EMC_TR_QSAFE 0x3fc -#define EMC_TR_QRST 0x400 -#define EMC_IBDLY 0x468 -#define EMC_OBDLY 0x46c -#define EMC_TXDSRVTTGEN 0x480 -#define EMC_WE_DURATION 0x48c -#define EMC_WS_DURATION 0x490 -#define EMC_WEV 0x494 -#define EMC_WSV 0x498 -#define EMC_CFG_3 0x49c -#define EMC_CFG_PIPE_2 0x554 -#define EMC_CFG_PIPE_CLK 0x558 -#define EMC_CFG_PIPE_1 0x55c -#define EMC_CFG_PIPE 0x560 -#define EMC_QPOP 0x564 -#define EMC_QUSE_WIDTH 0x568 -#define EMC_PUTERM_WIDTH 0x56c -#define EMC_PROTOBIST_CONFIG_ADR_1 0x5d0 -#define EMC_PROTOBIST_CONFIG_ADR_2 0x5d4 -#define EMC_PROTOBIST_MISC 0x5d8 -#define EMC_PROTOBIST_WDATA_LOWER 0x5dc -#define EMC_PROTOBIST_WDATA_UPPER 0x5e0 -#define EMC_PROTOBIST_RDATA 0x5ec -#define EMC_DLL_CFG_0 0x5e4 -#define EMC_DLL_CFG_1 0x5e8 -#define EMC_TRAINING_CMD 0xe00 -#define EMC_TRAINING_CTRL 0xe04 -#define EMC_TRAINING_STATUS 0xe08 -#define EMC_TRAINING_QUSE_CORS_CTRL 0xe0c -#define EMC_TRAINING_QUSE_FINE_CTRL 0xe10 -#define EMC_TRAINING_QUSE_CTRL_MISC 0xe14 -#define EMC_TRAINING_WRITE_FINE_CTRL 0xe18 -#define EMC_TRAINING_WRITE_CTRL_MISC 0xe1c -#define EMC_TRAINING_WRITE_VREF_CTRL 0xe20 -#define EMC_TRAINING_READ_FINE_CTRL 0xe24 -#define EMC_TRAINING_READ_CTRL_MISC 0xe28 -#define EMC_TRAINING_READ_VREF_CTRL 0xe2c -#define EMC_TRAINING_CA_FINE_CTRL 0xe30 -#define EMC_TRAINING_CA_CTRL_MISC 0xe34 -#define EMC_TRAINING_CA_CTRL_MISC1 0xe38 -#define EMC_TRAINING_CA_VREF_CTRL 0xe3c -#define EMC_TRAINING_CA_TADR_CTRL 0xe40 -#define EMC_TRAINING_SETTLE 0xe44 -#define EMC_TRAINING_DEBUG_CTRL 0xe48 -#define EMC_TRAINING_DEBUG_DQ0 0xe4c -#define EMC_TRAINING_DEBUG_DQ1 0xe50 -#define EMC_TRAINING_DEBUG_DQ2 0xe54 -#define EMC_TRAINING_DEBUG_DQ3 0xe58 -#define EMC_TRAINING_MPC 0xe5c -#define EMC_TRAINING_PATRAM_CTRL 0xe60 -#define EMC_TRAINING_PATRAM_DQ 0xe64 -#define EMC_TRAINING_PATRAM_DMI 0xe68 -#define EMC_TRAINING_VREF_SETTLE 0xe6c -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 0xe70 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 0xe74 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 0xe78 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 0xe7c -#define EMC_TRAINING_RW_EYE_CENTER_IB_MISC 0xe80 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 0xe84 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 0xe88 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 0xe8c -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 0xe90 -#define EMC_TRAINING_RW_EYE_CENTER_OB_MISC 0xe94 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE0 0xe98 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE1 0xe9c -#define EMC_TRAINING_RW_OFFSET_IB_BYTE2 0xea0 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE3 0xea4 -#define EMC_TRAINING_RW_OFFSET_IB_MISC 0xea8 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE0 0xeac -#define EMC_TRAINING_RW_OFFSET_OB_BYTE1 0xeb0 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE2 0xeb4 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE3 0xeb8 -#define EMC_TRAINING_RW_OFFSET_OB_MISC 0xebc -#define EMC_TRAINING_OPT_CA_VREF 0xec0 -#define EMC_TRAINING_OPT_DQ_OB_VREF 0xec4 -#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 0xec8 -#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 0xecc -#define EMC_TRAINING_QUSE_VREF_CTRL 0xed0 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 -#define EMC_TRAINING_DRAMC_TIMING 0xedc -#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 -#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 -#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 -#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60c -#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610 -#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614 -#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620 -#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624 -#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628 -#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62c -#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630 -#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64c -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66c -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68c -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6a0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6a4 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6a8 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6ac -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6b0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6b4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6c0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6c4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6c8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6cc -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 0x6d0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 0x6d4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6e0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6e4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6e8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6ec -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 0x6f0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 0x6f4 -#define EMC_PMACRO_TX_PWRD_0 0x720 -#define EMC_PMACRO_TX_PWRD_1 0x724 -#define EMC_PMACRO_TX_PWRD_2 0x728 -#define EMC_PMACRO_TX_PWRD_3 0x72c -#define EMC_PMACRO_TX_PWRD_4 0x730 -#define EMC_PMACRO_TX_PWRD_5 0x734 -#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740 -#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744 -#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74c -#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748 -#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750 -#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754 -#define EMC_PMACRO_DDLL_BYPASS 0x760 -#define EMC_PMACRO_DDLL_PWRD_0 0x770 -#define EMC_PMACRO_DDLL_PWRD_1 0x774 -#define EMC_PMACRO_DDLL_PWRD_2 0x778 -#define EMC_PMACRO_CMD_CTRL_0 0x780 -#define EMC_PMACRO_CMD_CTRL_1 0x784 -#define EMC_PMACRO_CMD_CTRL_2 0x788 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8a0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8a4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8a8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8ac -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8b0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8b4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8b8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8bc -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9a0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9a4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9a8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9ac -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9b0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9b4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9b8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9bc -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xa00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xa04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xa08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xa10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xa14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xa18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xa20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xa24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xa28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xa30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xa34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xa38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xa40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xa44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xa48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xa50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xa54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xa58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xa60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xa64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xa68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xa70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xa74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xa78 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 0xa80 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 0xa84 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 0xa88 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 0xa90 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 0xa94 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 0xa98 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 0xaa0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 0xaa4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 0xaa8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 0xab0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 0xab4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 0xab8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xb00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xb04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xb08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xb10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xb14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xb18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xb20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xb24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xb28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xb30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xb34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xb38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xb40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xb44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xb48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xb50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xb54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xb58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xb60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xb64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xb68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xb70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xb74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xb78 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 0xb80 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 0xb84 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 0xb88 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 0xb90 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 0xb94 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 0xb98 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 0xba0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 0xba4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 0xba8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 0xbb0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 0xbb4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 0xbb8 -#define EMC_PMACRO_IB_VREF_DQ_0 0xbe0 -#define EMC_PMACRO_IB_VREF_DQ_1 0xbe4 -#define EMC_PMACRO_IB_VREF_DQ_2 0xbe8 -#define EMC_PMACRO_IB_VREF_DQS_0 0xbf0 -#define EMC_PMACRO_IB_VREF_DQS_1 0xbf4 -#define EMC_PMACRO_IB_VREF_DQS_2 0xbf8 -#define EMC_PMACRO_IB_RXRT 0xcf4 -#define EMC_PMACRO_DDLL_LONG_CMD_0 0xc00 -#define EMC_PMACRO_DDLL_LONG_CMD_1 0xc04 -#define EMC_PMACRO_DDLL_LONG_CMD_2 0xc08 -#define EMC_PMACRO_DDLL_LONG_CMD_3 0xc0c -#define EMC_PMACRO_DDLL_LONG_CMD_4 0xc10 -#define EMC_PMACRO_DDLL_LONG_CMD_5 0xc14 -#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xc20 -#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xc24 -#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xc28 -#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xc30 -#define EMC_PMACRO_VTTGEN_CTRL_0 0xc34 -#define EMC_PMACRO_VTTGEN_CTRL_1 0xc38 -#define EMC_PMACRO_VTTGEN_CTRL_2 0xcf0 -#define EMC_PMACRO_BG_BIAS_CTRL_0 0xc3c -#define EMC_PMACRO_PAD_CFG_CTRL 0xc40 -#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xc50 -#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xc54 -#define EMC_PMACRO_CMD_RX_TERM_MODE 0xc58 -#define EMC_PMACRO_DATA_RX_TERM_MODE 0xc5c -#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 -#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 -#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 -#define EMC_PMACRO_BRICK_MAPPING_0 0xc80 -#define EMC_PMACRO_BRICK_MAPPING_1 0xc84 -#define EMC_PMACRO_BRICK_MAPPING_2 0xc88 -#define EMC_PMACRO_DDLLCAL_CAL 0xce0 -#define EMC_PMACRO_DDLL_OFFSET 0xce4 -#define EMC_PMACRO_DDLL_PERIODIC_OFFSET 0xce8 -#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330 -#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334 -#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318 -#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c -#define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 -#define EMC_PMACRO_TRAINING_CTRL_1 0xcfc -#define EMC_PMC_SCRATCH1 0x440 -#define EMC_PMC_SCRATCH2 0x444 -#define EMC_PMC_SCRATCH3 0x448 +#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO 0xccc +#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI 0xcd0 +#define EMC_STAT_DRAM_IO_DSR 0xcd4 +#define EMC_AUTO_CAL_CONFIG 0x2a4 +#define EMC_AUTO_CAL_CONFIG2 0x458 +#define EMC_AUTO_CAL_CONFIG3 0x45c +#define EMC_AUTO_CAL_CONFIG4 0x5b0 +#define EMC_AUTO_CAL_CONFIG5 0x5b4 +#define EMC_AUTO_CAL_CONFIG6 0x5cc +#define EMC_AUTO_CAL_CONFIG7 0x574 +#define EMC_AUTO_CAL_CONFIG8 0x2dc +#define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 +#define EMC_AUTO_CAL_VREF_SEL_1 0x300 +#define EMC_AUTO_CAL_INTERVAL 0x2a8 +#define EMC_AUTO_CAL_STATUS 0x2ac +#define EMC_AUTO_CAL_STATUS2 0x3d4 +#define EMC_AUTO_CAL_CHANNEL 0x464 +#define EMC_PMACRO_RX_TERM 0xc48 +#define EMC_PMACRO_DQ_TX_DRV 0xc70 +#define EMC_PMACRO_CA_TX_DRV 0xc74 +#define EMC_PMACRO_CMD_TX_DRV 0xc4c +#define EMC_PMACRO_AUTOCAL_CFG_0 0x700 +#define EMC_PMACRO_AUTOCAL_CFG_1 0x704 +#define EMC_PMACRO_AUTOCAL_CFG_2 0x708 +#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xc78 +#define EMC_PMACRO_ZCTRL 0xc44 +#define EMC_XM2COMPPADCTRL 0x30c +#define EMC_XM2COMPPADCTRL2 0x578 +#define EMC_XM2COMPPADCTRL3 0x2f4 +#define EMC_COMP_PAD_SW_CTRL 0x57c +#define EMC_REQ_CTRL 0x2b0 +#define EMC_EMC_STATUS 0x2b4 +#define EMC_STATUS_MRR_DIVLD (1 << 20) +#define EMC_CFG_2 0x2b8 +#define EMC_CFG_DIG_DLL 0x2bc +#define EMC_CFG_DIG_DLL_PERIOD 0x2c0 +#define EMC_DIG_DLL_STATUS 0x2c4 +#define EMC_CFG_DIG_DLL_1 0x2c8 +#define EMC_RDV_MASK 0x2cc +#define EMC_WDV_MASK 0x2d0 +#define EMC_RDV_EARLY_MASK 0x2d4 +#define EMC_RDV_EARLY 0x2d8 +#define EMC_WDV_CHK 0x4e0 +#define EMC_ZCAL_INTERVAL 0x2e0 +#define EMC_ZCAL_WAIT_CNT 0x2e4 +#define EMC_ZCAL_MRW_CMD 0x2e8 +#define EMC_ZQ_CAL 0x2ec +#define EMC_SCRATCH0 0x324 +#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 0x3c8 +#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3cc +#define EMC_UNSTALL_RW_AFTER_CLKCHANGE 0x3d0 +#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4d8 +#define EMC_SEL_DPD_CTRL 0x3d8 +#define EMC_FDPD_CTRL_DQ 0x310 +#define EMC_FDPD_CTRL_CMD 0x314 +#define EMC_PRE_REFRESH_REQ_CNT 0x3dc +#define EMC_REFCTRL2 0x580 +#define EMC_FBIO_CFG7 0x584 +#define EMC_DATA_BRLSHFT_0 0x588 +#define EMC_DATA_BRLSHFT_1 0x58c +#define EMC_DQS_BRLSHFT_0 0x594 +#define EMC_DQS_BRLSHFT_1 0x598 +#define EMC_CMD_BRLSHFT_0 0x59c +#define EMC_CMD_BRLSHFT_1 0x5a0 +#define EMC_CMD_BRLSHFT_2 0x5a4 +#define EMC_CMD_BRLSHFT_3 0x5a8 +#define EMC_QUSE_BRLSHFT_0 0x5ac +#define EMC_QUSE_BRLSHFT_1 0x5b8 +#define EMC_QUSE_BRLSHFT_2 0x5bc +#define EMC_QUSE_BRLSHFT_3 0x5c4 +#define EMC_FBIO_CFG8 0x5c8 +#define EMC_CMD_MAPPING_CMD0_0 0x380 +#define EMC_CMD_MAPPING_CMD0_1 0x384 +#define EMC_CMD_MAPPING_CMD0_2 0x388 +#define EMC_CMD_MAPPING_CMD1_0 0x38c +#define EMC_CMD_MAPPING_CMD1_1 0x390 +#define EMC_CMD_MAPPING_CMD1_2 0x394 +#define EMC_CMD_MAPPING_CMD2_0 0x398 +#define EMC_CMD_MAPPING_CMD2_1 0x39c +#define EMC_CMD_MAPPING_CMD2_2 0x3a0 +#define EMC_CMD_MAPPING_CMD3_0 0x3a4 +#define EMC_CMD_MAPPING_CMD3_1 0x3a8 +#define EMC_CMD_MAPPING_CMD3_2 0x3ac +#define EMC_CMD_MAPPING_BYTE 0x3b0 +#define EMC_DYN_SELF_REF_CONTROL 0x3e0 +#define EMC_TXSRDLL 0x3e4 +#define EMC_CCFIFO_ADDR 0x3e8 +#define EMC_CCFIFO_DATA 0x3ec +#define EMC_CCFIFO_STATUS 0x3f0 +#define EMC_SWIZZLE_RANK0_BYTE0 0x404 +#define EMC_SWIZZLE_RANK0_BYTE1 0x408 +#define EMC_SWIZZLE_RANK0_BYTE2 0x40c +#define EMC_SWIZZLE_RANK0_BYTE3 0x410 +#define EMC_SWIZZLE_RANK1_BYTE0 0x418 +#define EMC_SWIZZLE_RANK1_BYTE1 0x41c +#define EMC_SWIZZLE_RANK1_BYTE2 0x420 +#define EMC_SWIZZLE_RANK1_BYTE3 0x424 +#define EMC_TR_TIMING_0 0x3b4 +#define EMC_TR_CTRL_0 0x3b8 +#define EMC_TR_CTRL_1 0x3bc +#define EMC_TR_DVFS 0x460 +#define EMC_SWITCH_BACK_CTRL 0x3c0 +#define EMC_TR_RDV 0x3c4 +#define EMC_TR_QPOP 0x3f4 +#define EMC_TR_RDV_MASK 0x3f8 +#define EMC_TR_QSAFE 0x3fc +#define EMC_TR_QRST 0x400 +#define EMC_IBDLY 0x468 +#define EMC_OBDLY 0x46c +#define EMC_TXDSRVTTGEN 0x480 +#define EMC_WE_DURATION 0x48c +#define EMC_WS_DURATION 0x490 +#define EMC_WEV 0x494 +#define EMC_WSV 0x498 +#define EMC_CFG_3 0x49c +#define EMC_CFG_PIPE_2 0x554 +#define EMC_CFG_PIPE_CLK 0x558 +#define EMC_CFG_PIPE_1 0x55c +#define EMC_CFG_PIPE 0x560 +#define EMC_QPOP 0x564 +#define EMC_QUSE_WIDTH 0x568 +#define EMC_PUTERM_WIDTH 0x56c +#define EMC_PROTOBIST_CONFIG_ADR_1 0x5d0 +#define EMC_PROTOBIST_CONFIG_ADR_2 0x5d4 +#define EMC_PROTOBIST_MISC 0x5d8 +#define EMC_PROTOBIST_WDATA_LOWER 0x5dc +#define EMC_PROTOBIST_WDATA_UPPER 0x5e0 +#define EMC_PROTOBIST_RDATA 0x5ec +#define EMC_DLL_CFG_0 0x5e4 +#define EMC_DLL_CFG_1 0x5e8 +#define EMC_TRAINING_CMD 0xe00 +#define EMC_TRAINING_CTRL 0xe04 +#define EMC_TRAINING_STATUS 0xe08 +#define EMC_TRAINING_QUSE_CORS_CTRL 0xe0c +#define EMC_TRAINING_QUSE_FINE_CTRL 0xe10 +#define EMC_TRAINING_QUSE_CTRL_MISC 0xe14 +#define EMC_TRAINING_WRITE_FINE_CTRL 0xe18 +#define EMC_TRAINING_WRITE_CTRL_MISC 0xe1c +#define EMC_TRAINING_WRITE_VREF_CTRL 0xe20 +#define EMC_TRAINING_READ_FINE_CTRL 0xe24 +#define EMC_TRAINING_READ_CTRL_MISC 0xe28 +#define EMC_TRAINING_READ_VREF_CTRL 0xe2c +#define EMC_TRAINING_CA_FINE_CTRL 0xe30 +#define EMC_TRAINING_CA_CTRL_MISC 0xe34 +#define EMC_TRAINING_CA_CTRL_MISC1 0xe38 +#define EMC_TRAINING_CA_VREF_CTRL 0xe3c +#define EMC_TRAINING_CA_TADR_CTRL 0xe40 +#define EMC_TRAINING_SETTLE 0xe44 +#define EMC_TRAINING_DEBUG_CTRL 0xe48 +#define EMC_TRAINING_DEBUG_DQ0 0xe4c +#define EMC_TRAINING_DEBUG_DQ1 0xe50 +#define EMC_TRAINING_DEBUG_DQ2 0xe54 +#define EMC_TRAINING_DEBUG_DQ3 0xe58 +#define EMC_TRAINING_MPC 0xe5c +#define EMC_TRAINING_PATRAM_CTRL 0xe60 +#define EMC_TRAINING_PATRAM_DQ 0xe64 +#define EMC_TRAINING_PATRAM_DMI 0xe68 +#define EMC_TRAINING_VREF_SETTLE 0xe6c +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 0xe70 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 0xe74 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 0xe78 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 0xe7c +#define EMC_TRAINING_RW_EYE_CENTER_IB_MISC 0xe80 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 0xe84 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 0xe88 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 0xe8c +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 0xe90 +#define EMC_TRAINING_RW_EYE_CENTER_OB_MISC 0xe94 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE0 0xe98 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE1 0xe9c +#define EMC_TRAINING_RW_OFFSET_IB_BYTE2 0xea0 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE3 0xea4 +#define EMC_TRAINING_RW_OFFSET_IB_MISC 0xea8 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE0 0xeac +#define EMC_TRAINING_RW_OFFSET_OB_BYTE1 0xeb0 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE2 0xeb4 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE3 0xeb8 +#define EMC_TRAINING_RW_OFFSET_OB_MISC 0xebc +#define EMC_TRAINING_OPT_CA_VREF 0xec0 +#define EMC_TRAINING_OPT_DQ_OB_VREF 0xec4 +#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 0xec8 +#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 0xecc +#define EMC_TRAINING_QUSE_VREF_CTRL 0xed0 +#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 +#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 +#define EMC_TRAINING_DRAMC_TIMING 0xedc +#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 +#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 +#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 +#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60c +#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610 +#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614 +#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620 +#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624 +#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628 +#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62c +#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630 +#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64c +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66c +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68c +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6a0 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6a4 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6a8 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6ac +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6b0 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6b4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6c0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6c4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6c8 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6cc +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 0x6d0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 0x6d4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6e0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6e4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6e8 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6ec +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 0x6f0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 0x6f4 +#define EMC_PMACRO_TX_PWRD_0 0x720 +#define EMC_PMACRO_TX_PWRD_1 0x724 +#define EMC_PMACRO_TX_PWRD_2 0x728 +#define EMC_PMACRO_TX_PWRD_3 0x72c +#define EMC_PMACRO_TX_PWRD_4 0x730 +#define EMC_PMACRO_TX_PWRD_5 0x734 +#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740 +#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744 +#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74c +#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748 +#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750 +#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754 +#define EMC_PMACRO_DDLL_BYPASS 0x760 +#define EMC_PMACRO_DDLL_PWRD_0 0x770 +#define EMC_PMACRO_DDLL_PWRD_1 0x774 +#define EMC_PMACRO_DDLL_PWRD_2 0x778 +#define EMC_PMACRO_CMD_CTRL_0 0x780 +#define EMC_PMACRO_CMD_CTRL_1 0x784 +#define EMC_PMACRO_CMD_CTRL_2 0x788 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8a0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8a4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8a8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8ac +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8b0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8b4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8b8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8bc +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9a0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9a4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9a8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9ac +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9b0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9b4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9b8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9bc +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xa00 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xa04 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xa08 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xa10 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xa14 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xa18 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xa20 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xa24 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xa28 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xa30 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xa34 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xa38 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xa40 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xa44 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xa48 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xa50 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xa54 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xa58 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xa60 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xa64 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xa68 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xa70 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xa74 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xa78 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 0xa80 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 0xa84 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 0xa88 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 0xa90 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 0xa94 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 0xa98 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 0xaa0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 0xaa4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 0xaa8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 0xab0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 0xab4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 0xab8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xb00 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xb04 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xb08 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xb10 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xb14 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xb18 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xb20 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xb24 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xb28 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xb30 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xb34 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xb38 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xb40 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xb44 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xb48 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xb50 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xb54 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xb58 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xb60 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xb64 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xb68 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xb70 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xb74 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xb78 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 0xb80 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 0xb84 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 0xb88 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 0xb90 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 0xb94 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 0xb98 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 0xba0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 0xba4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 0xba8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 0xbb0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 0xbb4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 0xbb8 +#define EMC_PMACRO_IB_VREF_DQ_0 0xbe0 +#define EMC_PMACRO_IB_VREF_DQ_1 0xbe4 +#define EMC_PMACRO_IB_VREF_DQ_2 0xbe8 +#define EMC_PMACRO_IB_VREF_DQS_0 0xbf0 +#define EMC_PMACRO_IB_VREF_DQS_1 0xbf4 +#define EMC_PMACRO_IB_VREF_DQS_2 0xbf8 +#define EMC_PMACRO_IB_RXRT 0xcf4 +#define EMC_PMACRO_DDLL_LONG_CMD_0 0xc00 +#define EMC_PMACRO_DDLL_LONG_CMD_1 0xc04 +#define EMC_PMACRO_DDLL_LONG_CMD_2 0xc08 +#define EMC_PMACRO_DDLL_LONG_CMD_3 0xc0c +#define EMC_PMACRO_DDLL_LONG_CMD_4 0xc10 +#define EMC_PMACRO_DDLL_LONG_CMD_5 0xc14 +#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xc20 +#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xc24 +#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xc28 +#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xc30 +#define EMC_PMACRO_VTTGEN_CTRL_0 0xc34 +#define EMC_PMACRO_VTTGEN_CTRL_1 0xc38 +#define EMC_PMACRO_VTTGEN_CTRL_2 0xcf0 +#define EMC_PMACRO_BG_BIAS_CTRL_0 0xc3c +#define EMC_PMACRO_PAD_CFG_CTRL 0xc40 +#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xc50 +#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xc54 +#define EMC_PMACRO_CMD_RX_TERM_MODE 0xc58 +#define EMC_PMACRO_DATA_RX_TERM_MODE 0xc5c +#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 +#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 +#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 +#define EMC_PMACRO_BRICK_MAPPING_0 0xc80 +#define EMC_PMACRO_BRICK_MAPPING_1 0xc84 +#define EMC_PMACRO_BRICK_MAPPING_2 0xc88 +#define EMC_PMACRO_DDLLCAL_CAL 0xce0 +#define EMC_PMACRO_DDLL_OFFSET 0xce4 +#define EMC_PMACRO_DDLL_PERIODIC_OFFSET 0xce8 +#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330 +#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334 +#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318 +#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c +#define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 +#define EMC_PMACRO_TRAINING_CTRL_1 0xcfc +#define EMC_PMC_SCRATCH1 0x440 +#define EMC_PMC_SCRATCH2 0x444 +#define EMC_PMC_SCRATCH3 0x448 + +#define EMC_STATUS_UPDATE_TIMEOUT 1000 + +typedef enum _emc_mr_t +{ + MR5_MAN_ID = 5, + MR6_REV_ID1 = 6, + MR7_REV_ID2 = 7, + MR8_DENSITY = 8, +} emc_mr_t; + +enum +{ + EMC_CHAN0 = 0, + EMC_CHAN1 = 1 +}; + +typedef struct _emc_mr_data_t +{ + u8 dev0_ch0; + u8 dev0_ch1; + u8 dev1_ch0; + u8 dev1_ch1; +} emc_mr_data_t; #endif diff --git a/source/mem/heap.c b/source/mem/heap.c index 4ed7230..7c0e202 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -136,7 +136,7 @@ void *malloc(u32 size) void *calloc(u32 num, u32 size) { void *res = (void *)_heap_alloc(&_heap, num * size); - memset(res, 0, num * size); + memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size. return res; } @@ -164,7 +164,7 @@ void heap_monitor(heap_monitor_t *mon, bool print_node_stats) count, node->used, (u32)node + sizeof(hnode_t), node->size); count++; - + if (node->next) node = node->next; else diff --git a/source/mem/mc_t210.h b/source/mem/mc_t210.h index 602915f..87fe2ca 100644 --- a/source/mem/mc_t210.h +++ b/source/mem/mc_t210.h @@ -463,4 +463,54 @@ #define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 #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 diff --git a/source/mem/minerva.c b/source/mem/minerva.c index 84efee0..2607c4b 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -27,6 +27,7 @@ #include "../soc/t210.h" extern volatile nyx_storage_t *nyx_str; +void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); u32 minerva_init() { @@ -37,7 +38,7 @@ u32 minerva_init() memset(mtc_cfg, 0, sizeof(mtc_config_t)); // 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->init_done = MTC_NEW_MAGIC; // Initialize mtc table. diff --git a/source/mem/minerva.h b/source/mem/minerva.h index 00228f4..9be55c9 100644 --- a/source/mem/minerva.h +++ b/source/mem/minerva.h @@ -57,7 +57,7 @@ typedef enum FREQ_1600 = 1600000 } minerva_freq_t; -void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); +extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); u32 minerva_init(); void minerva_change_freq(minerva_freq_t freq); void minerva_periodic_training(); diff --git a/source/mem/sdram.c b/source/mem/sdram.c index 3bc283d..36f54c1 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include + #include "mc.h" #include "emc.h" #include "sdram_param_t210.h" @@ -29,7 +31,7 @@ #include "../soc/t210.h" #include "../utils/util.h" -#define CONFIG_SDRAM_COMPRESS_CFG +#define CONFIG_SDRAM_KEEP_ALIVE #ifdef CONFIG_SDRAM_COMPRESS_CFG #include "../libs/compr/lz.h" @@ -40,13 +42,57 @@ 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. - if (sdram_id > 7) - sdram_id = 0; +static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) +{ + 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) @@ -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_MISC2) = 0; - // u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); +#ifdef CONFIG_SDRAM_KEEP_ALIVE + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = + (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE; +#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; while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000)) @@ -91,7 +141,7 @@ break_nosleep: if (params->emc_clock_source_dll) CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; 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_X_SET) = 0x4000; // Enable EMC_DLL clock. @@ -509,9 +559,9 @@ break_nosleep: // ZQ CAL setup (not actually issuing ZQ CAL now). 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; - 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_MRW_CMD) = params->emc_zcal_mrw_cmd; @@ -527,7 +577,7 @@ break_nosleep: // Set clock enable signal. 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; (void)EMC(EMC_PIN); @@ -536,9 +586,9 @@ break_nosleep: (void)EMC(EMC_PIN); } - if (params->memory_type == 3) + if (params->memory_type == MEMORY_TYPE_LPDDR4) 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); // Enable clock enable signal. @@ -547,15 +597,15 @@ break_nosleep: usleep(params->emc_pin_program_wait); // 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; // 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); // Init zq calibration, - if (params->memory_type == 3) + if (params->memory_type == MEMORY_TYPE_LPDDR4) { // Patch 6 using BCT spare variables. if (params->emc_bct_spare10) @@ -596,7 +646,7 @@ break_nosleep: PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; // 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_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_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; } +#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() { + // Check if id is proper. + u32 dramid = _get_sdram_id(); + if (dramid > 6) + dramid = 0; + #ifdef CONFIG_SDRAM_COMPRESS_CFG u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; 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 - 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 } diff --git a/source/mem/sdram.h b/source/mem/sdram.h index badc703..059bc9c 100644 --- a/source/mem/sdram.h +++ b/source/mem/sdram.h @@ -17,11 +17,13 @@ #ifndef _SDRAM_H_ #define _SDRAM_H_ +#include "emc.h" #include "sdram_param_t210.h" void sdram_init(); sdram_params_t *sdram_get_params(); sdram_params_t *sdram_get_params_patched(); void sdram_lp0_save_params(const void *params); +emc_mr_data_t sdram_read_mrx(emc_mr_t mrx); #endif diff --git a/source/mem/sdram_config.inl b/source/mem/sdram_config.inl index d23f4da..58eb62d 100644 --- a/source/mem/sdram_config.inl +++ b/source/mem/sdram_config.inl @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 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, @@ -14,1139 +15,683 @@ * along with this program. If not, see . */ -static const u8 _dram_cfg_0[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#define DRAM_ID(x) (1 << (x)) + +#define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH 0 +#define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN 1 +#define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2 +#define DRAM_4GB_COPPER_UNK_3 3 // Samsung? +#define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH 4 +#define DRAM_4GB_COPPER_UNK_5 5 // Samsung? +#define DRAM_4GB_COPPER_UNK_6 6 // Samsung? + +typedef struct _sdram_vendor_patch_t +{ + u32 val; + u16 addr:9; + u16 dramid:7; +} sdram_vendor_patch_t; + +static const sdram_params_t _dram_cfg_0_samsung_4gb = { + /* Specifies the type of memory device */ + .memory_type = MEMORY_TYPE_LPDDR4, + + /* MC/EMC clock source configuration */ + .pllm_input_divider = 0x00000001, // M div. + .pllm_feedback_divider = 0x00000022, // N div. + .pllm_stable_time = 0x0000012C, + .pllm_setup_control = 0x00000000, + .pllm_post_divider = 0x00000000, // P div. + .pllm_kcp = 0x00000000, + .pllm_kvco = 0x00000000, + + /* Spare BCT params */ + .emc_bct_spare0 = 0x00000000, + .emc_bct_spare1 = 0x00000000, + .emc_bct_spare2 = 0x00000000, + .emc_bct_spare3 = 0x00000000, + .emc_bct_spare4 = 0x7001BC68, // EMC_PMACRO_COMMON_PAD_TX_CTRL. + .emc_bct_spare5 = 0x0000000A, + .emc_bct_spare6 = 0x7001B404, // EMC_SWIZZLE_RANK0_BYTE0. + .emc_bct_spare7 = 0x76543201, + .emc_bct_spare8 = 0x7000E6C8, // APBDEV_PMC_WEAK_BIAS. + .emc_bct_spare9 = 0x00000000, + .emc_bct_spare10 = 0x00000000, + .emc_bct_spare11 = 0x00000000, + .emc_bct_spare12 = 0x00000000, // Used to hold EMC_PMACRO_BG_BIAS_CTRL. + .emc_bct_spare13 = 0x00000034, + + /* EMC clock configuration */ + .emc_clock_source = 0x40188002, + .emc_clock_source_dll = 0x40000000, + + .clk_rst_pllm_misc20_override = 0x00000000, + .clk_rst_pllm_misc20_override_enable = 0x00000000, + + .clear_clock2_mc1 = 0x00000000, + + /* Auto-calibration of EMC pads */ + .emc_auto_cal_interval = 0x001FFFFF, + + .emc_auto_cal_config = 0xA01A51D8, + .emc_auto_cal_config2 = 0x05500000, + .emc_auto_cal_config3 = 0x00770000, + + .emc_auto_cal_config4 = 0x00770000, + .emc_auto_cal_config5 = 0x00770000, + .emc_auto_cal_config6 = 0x00770000, + .emc_auto_cal_config7 = 0x00770000, + .emc_auto_cal_config8 = 0x00770000, + + .emc_auto_cal_vref_sel0 = 0xB3AFA6A6, + .emc_auto_cal_vref_sel1 = 0x00009E3C, + + .emc_auto_cal_channel = 0xC1E00303, + + .emc_pmacro_auto_cal_cfg0 = 0x04040404, + .emc_pmacro_auto_cal_cfg1 = 0x04040404, + .emc_pmacro_auto_cal_cfg2 = 0x00000000, + + .emc_pmacro_rx_term = 0x1F1F1F1F, + .emc_pmacro_dq_tx_drive = 0x1F1F1F1F, + .emc_pmacro_ca_tx_drive = 0x1F1F1F1F, + .emc_pmacro_cmd_tx_drive = 0x00001F1F, + .emc_pmacro_auto_cal_common = 0x00000804, + .emc_pmacro_zcrtl = 0x00000550, + + /* Specifies the time for the calibration to stabilize (in microseconds) */ + .emc_auto_cal_wait = 0x000001A1, + + .emc_xm2_comp_pad_ctrl = 0x00000032, + .emc_xm2_comp_pad_ctrl2 = 0x00000000, + .emc_xm2_comp_pad_ctrl3 = 0x00000000, + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + .emc_adr_cfg = 0x00000001, + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + .emc_pin_program_wait = 0x00000002, + /* Specifies the extra delay before/after pin RESET/CKE command */ + .emc_pin_extra_wait = 0x00000000, + + .emc_pin_gpio_enable = 0x00000003, + .emc_pin_gpio = 0x00000003, + + /* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */ + .emc_timing_control_wait = 0x0000001E, + + /* Timing parameters required for the SDRAM */ + .emc_rc = 0x0000000D, + .emc_rfc = 0x00000025, + .emc_rfc_pb = 0x00000013, + .emc_ref_ctrl2 = 0x00000000, + .emc_rfc_slr = 0x00000000, + .emc_ras = 0x00000009, + .emc_rp = 0x00000004, + .emc_r2r = 0x00000000, + .emc_w2w = 0x00000000, + .emc_r2w = 0x0000000B, + .emc_w2r = 0x0000000D, + .emc_r2p = 0x00000008, + .emc_w2p = 0x0000000B, + .emc_tppd = 0x00000004, + .emc_ccdmw = 0x00000020, + .emc_rd_rcd = 0x00000006, + .emc_wr_rcd = 0x00000006, + .emc_rrd = 0x00000006, + .emc_rext = 0x00000003, + .emc_wext = 0x00000000, + .emc_wdv = 0x00000004, + .emc_wdv_chk = 0x00000006, + .emc_wsv = 0x00000002, + .emc_wev = 0x00000000, + .emc_wdv_mask = 0x00000004, + .emc_ws_duration = 0x00000008, + .emc_we_duration = 0x0000000D, + .emc_quse = 0x00000005, + .emc_quse_width = 0x00000006, + .emc_ibdly = 0x00000000, + .emc_obdly = 0x00000000, + .emc_einput = 0x00000002, + .emc_einput_duration = 0x0000000D, + .emc_puterm_extra = 0x00000000, + .emc_puterm_width = 0x0000000B, + .emc_qrst = 0x00010000, + .emc_qsafe = 0x00000012, + .emc_rdv = 0x00000014, + .emc_rdv_mask = 0x00000016, + .emc_rdv_early = 0x00000012, + .emc_rdv_early_mask = 0x00000014, + .emc_qpop = 0x0000000A, + .emc_refresh = 0x00000304, + .emc_burst_refresh_num = 0x00000000, + .emc_prerefresh_req_cnt = 0x000000C1, + .emc_pdex2wr = 0x00000008, + .emc_pdex2rd = 0x00000008, + .emc_pchg2pden = 0x00000003, + .emc_act2pden = 0x00000003, + .emc_ar2pden = 0x00000003, + .emc_rw2pden = 0x00000014, + .emc_cke2pden = 0x00000005, + .emc_pdex2che = 0x00000002, + .emc_pdex2mrr = 0x0000000D, + .emc_txsr = 0x00000027, + .emc_txsr_dll = 0x00000027, + .emc_tcke = 0x00000005, + .emc_tckesr = 0x00000005, + .emc_tpd = 0x00000004, + .emc_tfaw = 0x00000009, + .emc_trpab = 0x00000005, + .emc_tclkstable = 0x00000004, + .emc_tclkstop = 0x00000009, + .emc_trefbw = 0x0000031C, + + /* FBIO configuration values */ + .emc_fbio_cfg5 = 0x9160A00D, + .emc_fbio_cfg7 = 0x00003BBF, + .emc_fbio_cfg8 = 0x0CF30000, + + /* Command mapping for CMD brick 0 */ + .emc_cmd_mapping_cmd0_0 = 0x061B0504, + .emc_cmd_mapping_cmd0_1 = 0x1C070302, + .emc_cmd_mapping_cmd0_2 = 0x05252523, + .emc_cmd_mapping_cmd1_0 = 0x0A091D08, + .emc_cmd_mapping_cmd1_1 = 0x0D1E0B24, + .emc_cmd_mapping_cmd1_2 = 0x0326260C, + .emc_cmd_mapping_cmd2_0 = 0x231C1B02, + .emc_cmd_mapping_cmd2_1 = 0x05070403, + .emc_cmd_mapping_cmd2_2 = 0x02252506, + .emc_cmd_mapping_cmd3_0 = 0x0D1D0B0A, + .emc_cmd_mapping_cmd3_1 = 0x1E090C08, + .emc_cmd_mapping_cmd3_2 = 0x08262624, + .emc_cmd_mapping_byte = 0x9A070624, + + .emc_fbio_spare = 0x00000012, + .emc_cfg_rsv = 0xFF00FF00, + + /* MRS command values */ + .emc_mrs = 0x00000000, + .emc_emrs = 0x00000000, + .emc_emrs2 = 0x00000000, + .emc_emrs3 = 0x00000000, + .emc_mrw1 = 0x08010004, + .emc_mrw2 = 0x08020000, + .emc_mrw3 = 0x080D0000, + .emc_mrw4 = 0xC0000000, + .emc_mrw6 = 0x08037171, + .emc_mrw8 = 0x080B0000, + .emc_mrw9 = 0x0C0E7272, + .emc_mrw10 = 0x00000000, + .emc_mrw12 = 0x0C0D0808, + .emc_mrw13 = 0x0C0D0000, + .emc_mrw14 = 0x08161414, + .emc_mrw_extra = 0x08010004, + .emc_warm_boot_mrw_extra = 0x08110000, + .emc_warm_boot_extramode_reg_write_enable = 0x00000001, + .emc_extramode_reg_write_enable = 0x00000000, + .emc_mrw_reset_command = 0x00000000, + .emc_mrw_reset_ninit_wait = 0x00000000, + .emc_mrs_wait_cnt = 0x00CC0015, + .emc_mrs_wait_cnt2 = 0x0033000A, + + /* EMC miscellaneous configurations */ + .emc_cfg = 0xF3200000, + .emc_cfg2 = 0x00110805, + .emc_cfg_pipe = 0x0FFF0FFF, + .emc_cfg_pipe_clk = 0x00000000, + .emc_fdpd_ctrl_cmd_no_ramp = 0x00000001, + .emc_cfg_update = 0x70000301, + .emc_dbg = 0x01000C00, + .emc_dbg_write_mux = 0x00000001, + .emc_cmd_q = 0x10004408, + .emc_mc2emc_q = 0x06000404, + .emc_dyn_self_ref_control = 0x80000713, + .ahb_arbitration_xbar_ctrl_meminit_done = 0x00000001, + .emc_cfg_dig_dll = 0x002C00A0, + .emc_cfg_dig_dll_1 = 0x00003701, + .emc_cfg_dig_dll_period = 0x00008000, + .emc_dev_select = 0x00000000, + .emc_sel_dpd_ctrl = 0x00040008, + + /* Pads trimmer delays */ + .emc_fdpd_ctrl_dq = 0x8020221F, + .emc_fdpd_ctrl_cmd = 0x0220F40F, + .emc_pmacro_ib_vref_dq_0 = 0x28282828, + .emc_pmacro_ib_vref_dq_1 = 0x28282828, + .emc_pmacro_ib_vref_dqs_0 = 0x11111111, + .emc_pmacro_ib_vref_dqs_1 = 0x11111111, + .emc_pmacro_ib_rxrt = 0x000000BE, + .emc_cfg_pipe1 = 0x0FFF0FFF, + .emc_cfg_pipe2 = 0x0FFF0FFF, + + .emc_pmacro_quse_ddll_rank0_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_5 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_5 = 0x00000000, + + .emc_pmacro_ob_ddll_long_dq_rank0_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank0_5 = 0x00140010, + .emc_pmacro_ob_ddll_long_dq_rank1_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank1_5 = 0x00140010, + + .emc_pmacro_ob_ddll_long_dqs_rank0_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank0_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank0_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank0_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank0_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank0_5 = 0x00000000, + .emc_pmacro_ob_ddll_long_dqs_rank1_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank1_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank1_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank1_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank1_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank1_5 = 0x00000000, + + .emc_pmacro_ib_ddll_long_dqs_rank0_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_3 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_3 = 0x00280028, + + .emc_pmacro_ddll_long_cmd_0 = 0x00140014, + .emc_pmacro_ddll_long_cmd_1 = 0x00120012, + .emc_pmacro_ddll_long_cmd_2 = 0x00100010, + .emc_pmacro_ddll_long_cmd_3 = 0x00140014, + .emc_pmacro_ddll_long_cmd_4 = 0x00000014, + .emc_pmacro_ddll_short_cmd_0 = 0x00000000, + .emc_pmacro_ddll_short_cmd_1 = 0x00000000, + .emc_pmacro_ddll_short_cmd_2 = 0x00000000, + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + .warm_boot_wait = 0x00000001, + + .emc_odt_write = 0x00000000, + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + .emc_zcal_interval = 0x00064000, + .emc_zcal_wait_cnt = 0x000900CC, + .emc_zcal_mrw_cmd = 0x0051004F, + + /* DRAM initialization sequence flow control */ + .emc_mrs_reset_dll = 0x00000000, + .emc_zcal_init_dev0 = 0x80000001, + .emc_zcal_init_dev1 = 0x40000001, + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + .emc_zcal_init_wait = 0x00000001, + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + .emc_zcal_warm_cold_boot_enables = 0x00000003, + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + .emc_mrw_lpddr2zcal_warm_boot = 0x040A00AB, + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + .emc_zqcal_ddr3_warm_boot = 0x00000011, + .emc_zqcal_lpddr4_warm_boot = 0x00000001, + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + .emc_zcal_warm_boot_wait = 0x00000001, + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + .emc_mrs_warm_boot_enable = 0x00000001, + .emc_mrs_reset_dll_wait = 0x00000000, + .emc_mrs_extra = 0x00000000, + .emc_warm_boot_mrs_extra = 0x00000000, + .emc_emrs_ddr2_dll_enable = 0x00000000, + .emc_mrs_ddr2_dll_reset = 0x00000000, + .emc_emrs_ddr2_ocd_calib = 0x00000000, + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + .emc_ddr2_wait = 0x00000000, + .emc_clken_override = 0x00000000, + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + .emc_extra_refresh_num = 0x00000002, + .emc_clken_override_allwarm_boot = 0x00000000, + .mc_clken_override_allwarm_boot = 0x00000000, + /* Specifies digital dll period, choosing between 4 to 64 ms */ + .emc_cfg_dig_dll_period_warm_boot = 0x00000003, + + /* Pad controls */ + .pmc_vddp_sel = 0x00000001, + .pmc_vddp_sel_wait = 0x00000002, + .pmc_ddr_pwr = 0x0000000F, + .pmc_ddr_cfg = 0x04220100, + .pmc_io_dpd3_req = 0x4FAFFFFF, + .pmc_io_dpd3_req_wait = 0x00000001, + .pmc_io_dpd4_req_wait = 0x00000002, + .pmc_reg_short = 0x00000000, + .pmc_no_io_power = 0x00000000, + .pmc_ddr_ctrl_wait = 0x00000000, + .pmc_ddr_ctrl = 0x0007FF8B, + .emc_acpd_control = 0x00000000, + + .emc_swizzle_rank0_byte0 = 0x76543201, + .emc_swizzle_rank0_byte1 = 0x65324710, + .emc_swizzle_rank0_byte2 = 0x25763410, + .emc_swizzle_rank0_byte3 = 0x25673401, + .emc_swizzle_rank1_byte0 = 0x32647501, + .emc_swizzle_rank1_byte1 = 0x34567201, + .emc_swizzle_rank1_byte2 = 0x56742310, + .emc_swizzle_rank1_byte3 = 0x67324501, + + .emc_txdsrvttgen = 0x00000000, + + .emc_data_brlshft0 = 0x00249249, + .emc_data_brlshft1 = 0x00249249, + + .emc_dqs_brlshft0 = 0x00000000, + .emc_dqs_brlshft1 = 0x00000000, + + .emc_cmd_brlshft0 = 0x00000000, + .emc_cmd_brlshft1 = 0x00000000, + .emc_cmd_brlshft2 = 0x0000001B, + .emc_cmd_brlshft3 = 0x0000001B, + + .emc_quse_brlshft0 = 0x00000000, + .emc_quse_brlshft1 = 0x00000000, + .emc_quse_brlshft2 = 0x00000000, + .emc_quse_brlshft3 = 0x00000000, + + .emc_dll_cfg0 = 0x1F13412F, + .emc_dll_cfg1 = 0x00010014, + + .emc_pmc_scratch1 = 0x4FAFFFFF, + .emc_pmc_scratch2 = 0x7FFFFFFF, + .emc_pmc_scratch3 = 0x4006D70B, + + .emc_pmacro_pad_cfg_ctrl = 0x00020000, + .emc_pmacro_vttgen_ctrl0 = 0x00030808, + .emc_pmacro_vttgen_ctrl1 = 0x00015C00, + .emc_pmacro_vttgen_ctrl2 = 0x00101010, + .emc_pmacro_brick_ctrl_rfu1 = 0x00001600, + .emc_pmacro_cmd_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_brick_ctrl_rfu2 = 0x00000000, + .emc_pmacro_data_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_bg_bias_ctrl0 = 0x00000034, + .emc_pmacro_data_pad_rx_ctrl = 0x00050037, + .emc_pmacro_cmd_pad_rx_ctrl = 0x00000000, + .emc_pmacro_data_rx_term_mode = 0x00000010, + .emc_pmacro_cmd_rx_term_mode = 0x00003000, + .emc_pmacro_data_pad_tx_ctrl = 0x02000111, + .emc_pmacro_common_pad_tx_ctrl = 0x00000008, + .emc_pmacro_cmd_pad_tx_ctrl = 0x0A000000, + + .emc_cfg3 = 0x00000040, + + .emc_pmacro_tx_pwrd0 = 0x10000000, + .emc_pmacro_tx_pwrd1 = 0x08000000, + .emc_pmacro_tx_pwrd2 = 0x08000000, + .emc_pmacro_tx_pwrd3 = 0x00000000, + .emc_pmacro_tx_pwrd4 = 0x00000000, + .emc_pmacro_tx_pwrd5 = 0x00001000, + + .emc_config_sample_delay = 0x00000020, + + .emc_pmacro_brick_mapping0 = 0x28091081, + .emc_pmacro_brick_mapping1 = 0x44A53293, + .emc_pmacro_brick_mapping2 = 0x76678A5B, + + .emc_pmacro_tx_sel_clk_src0 = 0x00000000, + .emc_pmacro_tx_sel_clk_src1 = 0x00000000, + .emc_pmacro_tx_sel_clk_src2 = 0x00000000, + .emc_pmacro_tx_sel_clk_src3 = 0x00000000, + .emc_pmacro_tx_sel_clk_src4 = 0x00000000, + .emc_pmacro_tx_sel_clk_src5 = 0x00000000, + + .emc_pmacro_ddll_bypass = 0xEFFFEFFF, + + .emc_pmacro_ddll_pwrd0 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd1 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd2 = 0xDCDCDCDC, + + .emc_pmacro_cmd_ctrl0 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl1 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl2 = 0x0A0A0A0A, + + /* DRAM size information */ + .mc_emem_adr_cfg = 0x00000001, + .mc_emem_adr_cfg_dev0 = 0x00070302, + .mc_emem_adr_cfg_dev1 = 0x00070302, + .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, + .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, + .mc_emem_adr_cfg_bank_mask1 = 0x39722800, + .mc_emem_adr_cfg_bank_mask2 = 0x4B9C1000, + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + .mc_emem_cfg = 0x00001000, + + /* MC arbitration configuration */ + .mc_emem_arb_cfg = 0x08000001, + .mc_emem_arb_outstanding_req = 0x8000004C, + .emc_emem_arb_refpb_hp_ctrl = 0x000A1020, + .emc_emem_arb_refpb_bank_ctrl = 0x80001028, + + .mc_emem_arb_timing_rcd = 0x00000001, + .mc_emem_arb_timing_rp = 0x00000000, + .mc_emem_arb_timing_rc = 0x00000003, + .mc_emem_arb_timing_ras = 0x00000001, + .mc_emem_arb_timing_faw = 0x00000002, + .mc_emem_arb_timing_rrd = 0x00000001, + .mc_emem_arb_timing_rap2pre = 0x00000002, + .mc_emem_arb_timing_wap2pre = 0x00000005, + .mc_emem_arb_timing_r2r = 0x00000002, + .mc_emem_arb_timing_w2w = 0x00000001, + .mc_emem_arb_timing_r2w = 0x00000004, + .mc_emem_arb_timing_w2r = 0x00000005, + .mc_emem_arb_timing_rfcpb = 0x00000004, + + .mc_emem_arb_da_turns = 0x02020001, + .mc_emem_arb_da_covers = 0x00030201, + .mc_emem_arb_misc0 = 0x71C30504, + .mc_emem_arb_misc1 = 0x70000F0F, + .mc_emem_arb_misc2 = 0x00000000, + + .mc_emem_arb_ring1_throttle = 0x001F0000, + .mc_emem_arb_override = 0x10000000, + .mc_emem_arb_override1 = 0x00000000, + .mc_emem_arb_rsv = 0xFF00FF00, + + .mc_da_cfg0 = 0x00000001, + .mc_emem_arb_timing_ccdmw = 0x00000008, + + .mc_clken_override = 0x00008000, + + .mc_stat_control = 0x00000000, + .mc_video_protect_bom = 0xFFF00000, + .mc_video_protect_bom_adr_hi = 0x00000000, + .mc_video_protect_size_mb = 0x00000000, + .mc_video_protect_vpr_override = 0xE4BAC343, + .mc_video_protect_vpr_override1 = 0x00001ED3, + .mc_video_protect_gpu_override0 = 0x00000000, + .mc_video_protect_gpu_override1 = 0x00000000, + .mc_sec_carveout_bom = 0xFFF00000, + .mc_sec_carveout_adr_hi = 0x00000000, + .mc_sec_carveout_size_mb = 0x00000000, + .mc_video_protect_write_access = 0x00000000, + .mc_sec_carveout_protect_write_access = 0x00000000, + + .mc_generalized_carveout1_bom = 0x00000000, + .mc_generalized_carveout1_bom_hi = 0x00000000, + .mc_generalized_carveout1_size_128kb = 0x00000008, + .mc_generalized_carveout1_access0 = 0x00000000, + .mc_generalized_carveout1_access1 = 0x00000000, + .mc_generalized_carveout1_access2 = 0x00300000, + .mc_generalized_carveout1_access3 = 0x03000000, + .mc_generalized_carveout1_access4 = 0x00000000, + .mc_generalized_carveout1_force_internal_access0 = 0x00000000, + .mc_generalized_carveout1_force_internal_access1 = 0x00000000, + .mc_generalized_carveout1_force_internal_access2 = 0x00000000, + .mc_generalized_carveout1_force_internal_access3 = 0x00000000, + .mc_generalized_carveout1_force_internal_access4 = 0x00000000, + .mc_generalized_carveout1_cfg0 = 0x04000C76, + + .mc_generalized_carveout2_bom = 0x00000000, + .mc_generalized_carveout2_bom_hi = 0x00000000, + .mc_generalized_carveout2_size_128kb = 0x00000002, + .mc_generalized_carveout2_access0 = 0x00000000, + .mc_generalized_carveout2_access1 = 0x00000000, + .mc_generalized_carveout2_access2 = 0x03000000, + .mc_generalized_carveout2_access3 = 0x00000000, + .mc_generalized_carveout2_access4 = 0x00000300, + .mc_generalized_carveout2_force_internal_access0 = 0x00000000, + .mc_generalized_carveout2_force_internal_access1 = 0x00000000, + .mc_generalized_carveout2_force_internal_access2 = 0x00000000, + .mc_generalized_carveout2_force_internal_access3 = 0x00000000, + .mc_generalized_carveout2_force_internal_access4 = 0x00000000, + .mc_generalized_carveout2_cfg0 = 0x0440167E, + + .mc_generalized_carveout3_bom = 0x00000000, + .mc_generalized_carveout3_bom_hi = 0x00000000, + .mc_generalized_carveout3_size_128kb = 0x00000000, + .mc_generalized_carveout3_access0 = 0x00000000, + .mc_generalized_carveout3_access1 = 0x00000000, + .mc_generalized_carveout3_access2 = 0x03000000, + .mc_generalized_carveout3_access3 = 0x00000000, + .mc_generalized_carveout3_access4 = 0x00000300, + .mc_generalized_carveout3_force_internal_access0 = 0x00000000, + .mc_generalized_carveout3_force_internal_access1 = 0x00000000, + .mc_generalized_carveout3_force_internal_access2 = 0x00000000, + .mc_generalized_carveout3_force_internal_access3 = 0x00000000, + .mc_generalized_carveout3_force_internal_access4 = 0x00000000, + .mc_generalized_carveout3_cfg0 = 0x04401E7E, + + .mc_generalized_carveout4_bom = 0x00000000, + .mc_generalized_carveout4_bom_hi = 0x00000000, + .mc_generalized_carveout4_size_128kb = 0x00000008, + .mc_generalized_carveout4_access0 = 0x00000000, + .mc_generalized_carveout4_access1 = 0x00000000, + .mc_generalized_carveout4_access2 = 0x00300000, + .mc_generalized_carveout4_access3 = 0x00000000, + .mc_generalized_carveout4_access4 = 0x000000C0, + .mc_generalized_carveout4_force_internal_access0 = 0x00000000, + .mc_generalized_carveout4_force_internal_access1 = 0x00000000, + .mc_generalized_carveout4_force_internal_access2 = 0x00000000, + .mc_generalized_carveout4_force_internal_access3 = 0x00000000, + .mc_generalized_carveout4_force_internal_access4 = 0x00000000, + .mc_generalized_carveout4_cfg0 = 0x04002446, + + .mc_generalized_carveout5_bom = 0x00000000, + .mc_generalized_carveout5_bom_hi = 0x00000000, + .mc_generalized_carveout5_size_128kb = 0x00000008, + .mc_generalized_carveout5_access0 = 0x00000000, + .mc_generalized_carveout5_access1 = 0x00000000, + .mc_generalized_carveout5_access2 = 0x00300000, + .mc_generalized_carveout5_access3 = 0x00000000, + .mc_generalized_carveout5_access4 = 0x00000000, + .mc_generalized_carveout5_force_internal_access0 = 0x00000000, + .mc_generalized_carveout5_force_internal_access1 = 0x00000000, + .mc_generalized_carveout5_force_internal_access2 = 0x00000000, + .mc_generalized_carveout5_force_internal_access3 = 0x00000000, + .mc_generalized_carveout5_force_internal_access4 = 0x00000000, + .mc_generalized_carveout5_cfg0 = 0x04002C46, + + /* Specifies enable for CA training */ + .emc_ca_training_enable = 0x00000000, + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + .swizzle_rank_byte_encode = 0x000000EC, + + /* Specifies enable and offset for patched boot rom write */ + .boot_rom_patch_control = 0x00000000, + /* Specifies data for patched boot rom write */ + .boot_rom_patch_data = 0x00000000, + + .mc_mts_carveout_bom = 0xFFF00000, + .mc_mts_carveout_adr_hi = 0x00000000, + .mc_mts_carveout_size_mb = 0x00000000, + .mc_mts_carveout_reg_ctrl = 0x00000000 }; -static const u8 _dram_cfg_1[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 _dram_cfg_2[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 _dram_cfg_3[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 _dram_cfg_4[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0C, 0x00, - 0x02, 0x03, 0x0C, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x18, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 _dram_cfg_5[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, - 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, - 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, - 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x15, 0x00, 0x15, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, 0x16, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 _dram_cfg_6[1896] = { - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, - 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, - 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, - 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, - 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, - 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, - 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, - 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, - 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, - 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, - 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, - 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, - 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, - 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, - 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, - 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, - 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x15, 0x00, 0x15, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, 0x16, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, - 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, - 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, - 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, - 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, - 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, - 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xA3, 0x72, 0x0F, 0x0F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u32 *_dram_cfgs[7] = { - (const u32 *)_dram_cfg_0, - (const u32 *)_dram_cfg_1, - (const u32 *)_dram_cfg_2, - (const u32 *)_dram_cfg_3, - (const u32 *)_dram_cfg_4, - (const u32 *)_dram_cfg_5, - (const u32 *)_dram_cfg_6 +static const sdram_vendor_patch_t sdram_cfg_vendor_patches[] = { + { 0x0000003A, 59, DRAM_ID(6) }, // emc_rfc. Auto refresh. + { 0x0000001D, 60, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. + { 0x0000000D, 67, DRAM_ID(1) | DRAM_ID(5) }, // emc_r2w. + { 0x00000001, 91, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_extra. + { 0x80000000, 92, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_width. + { 0x00000012, 108, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. + { 0x0000003B, 112, DRAM_ID(6) }, // emc_txsr. + { 0x0000003B, 113, DRAM_ID(6) }, // emc_txsr_dll. + { 0x00000003, 119, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_tclkstable. + { 0x00120015, 205, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x00160012, 206, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x00120015, 211, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00160012, 212, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x002F0032, 213, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00310032, 214, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00360034, 215, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0033002F, 216, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x00000006, 217, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x002F0032, 219, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00310032, 220, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00360034, 221, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0033002F, 222, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x00000006, 223, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00150015, 233, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_0. + { 0x00120012, 235, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_2. + { 0x00160016, 236, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000015, 237, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4. + { 0x00000012, 295, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2. + { 0x00000012, 296, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3. + { 0x00000210, 317, DRAM_ID(1) | DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. + { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB sub-partition density. + { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB sub-partition density. + { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. + { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. + { 0x00000007, 370, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh. + { 0x72A30504, 373, DRAM_ID(6) } // mc_emem_arb_misc0. }; diff --git a/source/mem/sdram_param_t210.h b/source/mem/sdram_param_t210.h index d926fa4..4980918 100644 --- a/source/mem/sdram_param_t210.h +++ b/source/mem/sdram_param_t210.h @@ -26,12 +26,12 @@ #ifndef _SDRAM_PARAM_T210_H_ #define _SDRAM_PARAM_T210_H_ -#define MEMORY_TYPE_NONE 0 -#define MEMORY_TYPE_DDR 0 -#define MEMORY_TYPE_LPDDR 0 -#define MEMORY_TYPE_DDR2 0 +#define MEMORY_TYPE_NONE 0 +#define MEMORY_TYPE_DDR 0 +#define MEMORY_TYPE_LPDDR 0 +#define MEMORY_TYPE_DDR2 0 #define MEMORY_TYPE_LPDDR2 1 -#define MEMORY_TYPE_DDR3 2 +#define MEMORY_TYPE_DDR3L 2 #define MEMORY_TYPE_LPDDR4 3 /** diff --git a/source/power/max17050.h b/source/power/max17050.h index 30a7ca0..eb55e65 100644 --- a/source/power/max17050.h +++ b/source/power/max17050.h @@ -24,6 +24,8 @@ #ifndef __MAX17050_H_ #define __MAX17050_H_ +#include "../utils/types.h" + #define MAX17050_STATUS_BattAbsent (1 << 3) #define MAX17050_DEFAULT_SNS_RESISTOR 10000 @@ -128,5 +130,6 @@ enum MAX17050_reg { int max17050_get_property(enum MAX17050_reg reg, int *value); int max17050_fix_configuration(); +u32 max17050_get_cached_batt_volt(); #endif /* __MAX17050_H_ */ diff --git a/source/sec/se.c b/source/sec/se.c index d129eda..484f3c8 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -95,7 +95,12 @@ static int _se_wait() static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) { - se_ll_t *ll_dst = (se_ll_t *)(NYX_STORAGE_ADDR - 0x20), *ll_src = (se_ll_t *)(NYX_STORAGE_ADDR - 0x10); + static se_ll_t *ll_dst = NULL, *ll_src = NULL; + if (!ll_dst) + { + ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); + ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); + } if (dst) { @@ -339,10 +344,9 @@ int se_initialize_rng(u32 ks) SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001; - SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(DRBG_RO_ENT_SRC_LOCK_ENABLE) | - SE_RNG_SRC_CONFIG_RO_ENT_SRC(DRBG_RO_ENT_SRC_LOCK_ENABLE); + SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0); @@ -356,7 +360,7 @@ int se_generate_random(u32 ks, void *dst, u32 size) SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); u32 num_blocks = size >> 4; u32 aligned_size = num_blocks << 4; @@ -376,7 +380,7 @@ int se_generate_random_key(u32 ks_dst, u32 ks_src) SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(DRBG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(DRBG_SRC_ENTROPY); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); if (!_se_execute(OP_START, NULL, 0, NULL, 0)) diff --git a/source/sec/se_t210.h b/source/sec/se_t210.h index 3b610bc..01828c7 100644 --- a/source/sec/se_t210.h +++ b/source/sec/se_t210.h @@ -70,27 +70,26 @@ #define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT) #define SE_RNG_CONFIG_REG_OFFSET 0x340 -#define DRBG_MODE_SHIFT 0 -#define DRBG_MODE_NORMAL 0 -#define DRBG_MODE_FORCE_INSTANTION 1 -#define DRBG_MODE_FORCE_RESEED 2 -#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT) +#define RNG_MODE_SHIFT 0 +#define RNG_MODE_NORMAL 0 +#define RNG_MODE_FORCE_INSTANTION 1 +#define RNG_MODE_FORCE_RESEED 2 +#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 DRBG_RO_ENT_SRC_SHIFT 1 -#define DRBG_RO_ENT_SRC_ENABLE 1 -#define DRBG_RO_ENT_SRC_DISABLE 0 -#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT) -#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0 -#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1 -#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0 -#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_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 RNG_SRC_RO_ENT_SHIFT 1 +#define RNG_SRC_RO_ENT_ENABLE 1 +#define RNG_SRC_RO_ENT_DISABLE 0 +#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT) +#define RNG_SRC_RO_ENT_LOCK_SHIFT 0 +#define RNG_SRC_RO_ENT_LOCK_ENABLE 1 +#define RNG_SRC_RO_ENT_LOCK_DISABLE 0 +#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT) #define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 @@ -119,6 +118,8 @@ #define OP_DONE 1 #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_HASH_SHIFT 0 #define HASH_DISABLE 0 @@ -191,6 +192,7 @@ #define SRK 6 #define RSA_KEYTABLE 1 +#define AES_KEYTABLE 2 #define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT) #define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16 diff --git a/source/sec/tsec.c b/source/sec/tsec.c index 17cd623..0a8169e 100644 --- a/source/sec/tsec.c +++ b/source/sec/tsec.c @@ -18,6 +18,7 @@ #include +#include "../hos/hos.h" #include "../sec/tsec.h" #include "../sec/tsec_t210.h" #include "../sec/se_t210.h" diff --git a/source/soc/bpmp.c b/source/soc/bpmp.c index 94ce6d5..eea0de5 100644 --- a/source/soc/bpmp.c +++ b/source/soc/bpmp.c @@ -1,7 +1,7 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -22,56 +22,101 @@ #include "../../common/memory_map.h" #include "../utils/util.h" +#define BPMP_MMU_CACHE_LINE_SIZE 0x20 + #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_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_READ_BUFFER (1 << 11) +#define CFG_ENABLE_HANG_DETECT (1 << 12) #define CFG_FULL_LINE_DIRTY (1 << 13) #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 LOCK_LINE(x) (1 << x) + #define BPMP_CACHE_SIZE 0xC #define BPMP_CACHE_LFSR 0x10 + #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 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_DATA 0x24 + #define BPMP_CACHE_MAINT_REQ 0x28 #define MAINT_REQ_WAY_BITMAP(x) ((x) << 8) #define BPMP_CACHE_INT_MASK 0x40 #define BPMP_CACHE_INT_CLEAR 0x44 -#define INT_CLR_MAINT_DONE (1 << 0) - #define BPMP_CACHE_INT_RAW_EVENT 0x48 -#define INT_RAW_EVENT_MAINT_DONE (1 << 0) #define BPMP_CACHE_INT_STATUS 0x4C +#define INT_MAINT_DONE (1 << 0) +#define INT_MAINT_ERROR (1 << 1) #define BPMP_CACHE_RB_CFG 0x80 #define BPMP_CACHE_WB_CFG 0x84 #define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0 #define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 + #define BPMP_CACHE_MMU_CFG 0xAC +#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0) #define MMU_CFG_SEQ_EN (1 << 1) #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_CLR_ABORT (1 << 5) + #define BPMP_CACHE_MMU_CMD 0xB0 #define MMU_CMD_NOP 0 #define MMU_CMD_INIT 1 #define MMU_CMD_COPY_SHADOW 2 + #define BPMP_CACHE_MMU_ABORT_STAT 0xB4 +#define 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_ACTIVE_ENTRIES 0xBC -#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) -#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) -#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0 - -#define MMU_EN_CACHED (1 << 0) -#define MMU_EN_EXEC (1 << 1) -#define MMU_EN_READ (1 << 2) -#define MMU_EN_WRITE (1 << 3) +#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) +#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) +#define MMU_EN_CACHED (1 << 0) +#define MMU_EN_EXEC (1 << 1) +#define MMU_EN_READ (1 << 2) +#define MMU_EN_WRITE (1 << 3) bpmp_mmu_entry_t mmu_entries[] = { @@ -81,15 +126,15 @@ bpmp_mmu_entry_t mmu_entries[] = 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; - 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. 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); @@ -104,8 +149,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) if (entry->enable) { - mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK; - mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK; + mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE); + mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); mmu_entry->attr = entry->attr; 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() { - if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE) + if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE) return; // Init BPMP MMU. @@ -136,7 +181,8 @@ void bpmp_mmu_enable() bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); // 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. bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); @@ -144,7 +190,7 @@ void bpmp_mmu_enable() void bpmp_mmu_disable() { - if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) + if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)) return; // Clean and invalidate cache. @@ -154,7 +200,10 @@ void bpmp_mmu_disable() 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. 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz 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; +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) { 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. CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. - // Wait a bit for clock source change. - msleep(10); + msleep(1); // Wait a bit for clock source change. } - CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; - CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1. + // Configure and enable PLLC. + clock_enable_pllc(pll_divn[fid]); - while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK)) - ; - - CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div. - CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset. - - // Wait a bit for PLLC4 to stabilize. - msleep(10); - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3. - - bpmp_clock_set = fid; + // 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. } 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. - msleep(10); - - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3. - CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE; - bpmp_clock_set = BPMP_CLK_NORMAL; + // Disable PLLC to save power. + clock_disable_pllc(); } + bpmp_clock_set = fid; } // The following functions halt BPMP to reduce power while sleeping. diff --git a/source/soc/bpmp.h b/source/soc/bpmp.h index 4c1155e..aad901a 100644 --- a/source/soc/bpmp.h +++ b/source/soc/bpmp.h @@ -1,7 +1,7 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -21,14 +21,24 @@ #include "../utils/types.h" -#define BPMP_MMU_MAINT_CLEAN_WAY 17 -#define BPMP_MMU_MAINT_INVALID_WAY 18 -#define BPMP_MMU_MAINT_CLN_INV_WAY 19 +typedef enum +{ + 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 { - u32 min_addr; - u32 max_addr; + u32 start_addr; + u32 end_addr; u32 attr; u32 enable; } 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_enable(); void bpmp_mmu_disable(); +void bpmp_clk_rate_get(); void bpmp_clk_rate_set(bpmp_freq_t fid); void bpmp_usleep(u32 us); void bpmp_msleep(u32 ms); diff --git a/source/soc/clock.c b/source/soc/clock.c index dda6d4b..60a069b 100644 --- a/source/soc/clock.c +++ b/source/soc/clock.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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, @@ -19,6 +20,17 @@ #include "../utils/util.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 */ 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 } }; -//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[] = { /* 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 @@ -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. }; +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) { // Put clock into reset. @@ -112,6 +128,29 @@ void clock_enable_uart(u32 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) { clock_enable(&_clock_i2c[idx]); @@ -228,6 +267,51 @@ void clock_disable_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_SDMMC2_RST (1 << 9) #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 -static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) +typedef struct _clock_sdmmc_t +{ + 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 source = PLLP_OUT0; + u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; + + if (id > SDMMC_4) + return 0; // Get IO clock divisor. switch (val) { case 25000: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. break; case 26000: - *pout = 25500; + *pclock = 25500; divisor = 30; // 16 div. break; case 40800: - *pout = 40800; + *pclock = 40800; divisor = 18; // 10 div. break; case 50000: - *pout = 48000; + *pclock = 48000; divisor = 15; // 8.5 div. break; case 52000: - *pout = 51000; + *pclock = 51000; divisor = 14; // 8 div. break; case 100000: - *pout = 90667; + *pclock = 90667; divisor = 7; // 4.5 div. break; - case 200000: - *pout = 163200; + case 164000: + *pclock = 163200; divisor = 3; // 2.5 div. break; - case 208000: - *pout = 204000; + case 200000: + *pclock = 204000; divisor = 2; // 2 div. break; default: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. } - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; + _clock_sdmmc_table[id].clock = val; + _clock_sdmmc_table[id].real_clock = *pclock; + + // Set SDMMC legacy timeout clock. + _clock_sdmmc_config_legacy_tm(); // Set SDMMC clock. switch (id) @@ -437,70 +543,75 @@ static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) 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 { int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_host(pout, id, val); + _clock_sdmmc_config_clock_host(pclock, id, val); if (is_enabled) _clock_sdmmc_set_enable(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. switch (type) { - case 0: - *pout = 26000; + case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. + *pclock = 26000; *pdivisor = 66; break; - case 1: - *pout = 26000; + case SDHCI_TIMING_MMC_LS26: + *pclock = 26000; *pdivisor = 1; break; - case 2: - *pout = 52000; + case SDHCI_TIMING_MMC_HS52: + *pclock = 52000; *pdivisor = 1; break; - case 3: - case 4: - case 11: - *pout = 200000; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + *pclock = 200000; *pdivisor = 1; break; - case 5: - *pout = 25000; + case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz. + *pclock = 25000; *pdivisor = 64; break; - case 6: - case 8: - *pout = 25000; + case SDHCI_TIMING_SD_DS12: + case SDHCI_TIMING_UHS_SDR12: + *pclock = 25000; *pdivisor = 1; break; - case 7: - *pout = 50000; + case SDHCI_TIMING_SD_HS25: + case SDHCI_TIMING_UHS_SDR25: + *pclock = 50000; *pdivisor = 1; break; - case 10: - *pout = 100000; + case SDHCI_TIMING_UHS_SDR50: + *pclock = 100000; *pdivisor = 1; break; - case 13: - *pout = 40800; + case SDHCI_TIMING_UHS_SDR82: + *pclock = 164000; *pdivisor = 1; break; - case 14: - *pout = 200000; + case SDHCI_TIMING_UHS_DDR50: + *pclock = 40800; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz. + *pclock = 200000; *pdivisor = 2; break; } @@ -513,15 +624,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id) void clock_sdmmc_enable(u32 id, u32 val) { - u32 div = 0; + u32 clock = 0; if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(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_is_reset(id); - usleep((100000 + div - 1) / div); + usleep((100000 + clock - 1) / clock); _clock_sdmmc_clear_reset(id); _clock_sdmmc_is_reset(id); } diff --git a/source/soc/clock.h b/source/soc/clock.h index ce6a81d..a9b9f9a 100644 --- a/source/soc/clock.h +++ b/source/soc/clock.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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, @@ -35,11 +36,19 @@ #define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 #define CLK_RST_CONTROLLER_OSC_CTRL 0x50 #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_1 0x8C #define CLK_RST_CONTROLLER_PLLM_BASE 0x90 #define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #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_MISC1 0xD8 #define CLK_RST_CONTROLLER_PLLD_MISC 0xDC @@ -49,6 +58,7 @@ #define CLK_RST_CONTROLLER_PLLE_MISC 0xEC #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 #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_I2C1 0x124 #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_UARTD 0x1C0 #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_OUT_ENB_X 0x280 #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_CLK_SOURCE_MSELECT 0x3B4 #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_SOR1 0x410 #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_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_CLR 0x444 #define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 #define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 #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_PLLE_AUX 0x48C #define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 #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_SPARE_REG0 0x55C #define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 #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_PLLMB_BASE 0x5E8 #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_SDMMC_LEGACY_TM 0x694 #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_CLK_SOURCE_UARTAPE 0x710 #define CLK_NO_SOURCE 0x0 /*! 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_BASE_LOCK (1 << 27) #define PLLC4_BASE_IDDQ (1 << 18) #define PLLC4_OUT3_CLKEN (1 << 1) #define PLLC4_OUT3_RSTN_CLR (1 << 0) @@ -159,6 +189,8 @@ void clock_disable(const clock_t *clk); /*! Clock control for specific hardware portions. */ void clock_enable_fuse(bool enable); 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_disable_i2c(u32 idx); void clock_enable_se(); @@ -181,9 +213,11 @@ void clock_enable_coresight(); void clock_disable_coresight(); void clock_enable_pwm(); void clock_disable_pwm(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type); -int clock_sdmmc_is_not_reset_and_enabled(u32 id); +void clock_enable_pllc(u32 divn); +void clock_disable_pllc(); +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_disable(u32 id); diff --git a/source/soc/fuse.h b/source/soc/fuse.h index 9240b04..00ee63c 100644 --- a/source/soc/fuse.h +++ b/source/soc/fuse.h @@ -54,6 +54,7 @@ #define FUSE_PRIVATE_KEY3 0x1B0 #define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_RESERVED_SW 0x1C0 +#define FUSE_USB_CALIB 0x1F0 #define FUSE_SKU_DIRECT_CONFIG 0x1F4 #define FUSE_OPT_VENDOR_CODE 0x200 #define FUSE_OPT_FAB_CODE 0x204 @@ -63,6 +64,7 @@ #define FUSE_OPT_X_COORDINATE 0x214 #define FUSE_OPT_Y_COORDINATE 0x218 #define FUSE_GPU_IDDQ_CALIB 0x228 +#define FUSE_USB_CALIB_EXT 0x350 /*! Fuse commands. */ #define FUSE_READ 0x1 diff --git a/source/soc/gpio.c b/source/soc/gpio.c index 053c43a..9183a04 100644 --- a/source/soc/gpio.c +++ b/source/soc/gpio.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,81 +15,146 @@ * along with this program. If not, see . */ -#include "../soc/gpio.h" -#include "../soc/t210.h" +#include "gpio.h" +#include "irq.h" +#include "t210.h" -static const u16 _gpio_cnf[31] = { - 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 -}; +#define GPIO_BANK_IDX(port) (port >> 2) -static const u16 _gpio_oe[31] = { - 0x010, 0x014, 0x018, 0x01C, - 0x110, 0x114, 0x118, 0x11C, - 0x210, 0x214, 0x218, 0x21C, - 0x310, 0x314, 0x318, 0x31C, - 0x410, 0x414, 0x418, 0x41C, - 0x510, 0x514, 0x518, 0x51C, - 0x610, 0x614, 0x618, 0x61C, - 0x710, 0x714, 0x718 -}; +#define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2)) -static const u16 _gpio_out[31] = { - 0x020, 0x024, 0x028, 0x02C, - 0x120, 0x124, 0x128, 0x12C, - 0x220, 0x224, 0x228, 0x22C, - 0x320, 0x324, 0x328, 0x32C, - 0x420, 0x424, 0x428, 0x42C, - 0x520, 0x524, 0x528, 0x52C, - 0x620, 0x624, 0x628, 0x62C, - 0x720, 0x724, 0x728 -}; +#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2)) -static const u16 _gpio_in[31] = { - 0x030, 0x034, 0x038, 0x03C, - 0x130, 0x134, 0x138, 0x13C, - 0x230, 0x234, 0x238, 0x23C, - 0x330, 0x334, 0x338, 0x33C, - 0x430, 0x434, 0x438, 0x43C, - 0x530, 0x534, 0x538, 0x53C, - 0x630, 0x634, 0x638, 0x63C, - 0x730, 0x734, 0x738 +static u8 gpio_bank_irq_ids[8] = { + IRQ_GPIO1, IRQ_GPIO2, IRQ_GPIO3, IRQ_GPIO4, + IRQ_GPIO5, IRQ_GPIO6, IRQ_GPIO7, IRQ_GPIO8 }; void gpio_config(u32 port, u32 pins, int mode) { + u32 offset = GPIO_CNF_OFFSET(port); + if (mode) - GPIO(_gpio_cnf[port]) |= pins; + GPIO(offset) |= pins; else - GPIO(_gpio_cnf[port]) &= ~pins; - (void)GPIO(_gpio_cnf[port]); + GPIO(offset) &= ~pins; + + (void)GPIO(offset); // Commit the write. } void gpio_output_enable(u32 port, u32 pins, int enable) { + u32 port_offset = GPIO_OE_OFFSET(port); + if (enable) - GPIO(_gpio_oe[port]) |= pins; + GPIO(port_offset) |= pins; else - GPIO(_gpio_oe[port]) &= ~pins; - (void)GPIO(_gpio_oe[port]); + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. } void gpio_write(u32 port, u32 pins, int high) { + u32 port_offset = GPIO_OUT_OFFSET(port); + if (high) - GPIO(_gpio_out[port]) |= pins; + GPIO(port_offset) |= pins; else - GPIO(_gpio_out[port]) &= ~pins; - (void)GPIO(_gpio_out[port]); + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. } 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]; +} \ No newline at end of file diff --git a/source/soc/gpio.h b/source/soc/gpio.h index 83170b0..a7f999d 100644 --- a/source/soc/gpio.h +++ b/source/soc/gpio.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,10 +22,23 @@ #define GPIO_MODE_SPIO 0 #define GPIO_MODE_GPIO 1 + #define GPIO_OUTPUT_DISABLE 0 #define GPIO_OUTPUT_ENABLE 1 + +#define GPIO_IRQ_DISABLE 0 +#define GPIO_IRQ_ENABLE 1 + #define GPIO_LOW 0 #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). */ #define GPIO_PIN_0 (1 << 0) @@ -72,6 +86,10 @@ void gpio_config(u32 port, u32 pins, int mode); void gpio_output_enable(u32 port, u32 pins, int enable); 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 diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index a7703a2..8867ff2 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -34,10 +34,10 @@ #include "../power/max7762x.h" #include "../sec/se.h" #include "../sec/se_t210.h" +#include "../storage/nx_sd.h" #include "../storage/sdmmc.h" #include "../utils/util.h" -extern sdmmc_t sd_sdmmc; extern boot_cfg_t b_cfg; extern volatile nyx_storage_t *nyx_str; @@ -314,6 +314,9 @@ void config_hw() 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) diff --git a/source/soc/i2c.c b/source/soc/i2c.c index 94239b5..40ab097 100644 --- a/source/soc/i2c.c +++ b/source/soc/i2c.c @@ -38,21 +38,39 @@ static void _i2c_wait(vu32 *base) static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) { - if (size > 4) + if (size > 8) return 0; u32 tmp = 0; - memcpy(&tmp, buf, size); vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). - base[I2C_CMD_DATA1] = tmp; //Set value. + base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). + + 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. _i2c_wait(base); //Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + + u32 timeout = get_tmr_ms() + 1500; while (base[I2C_STATUS] & 0x100) - ; + { + if (get_tmr_ms() > timeout) + return 0; + } if (base[I2C_STATUS] << 28) return 0; @@ -71,8 +89,13 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) _i2c_wait(base); // Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + + u32 timeout = get_tmr_ms() + 1500; while (base[I2C_STATUS] & 0x100) - ; + { + if (get_tmr_ms() > timeout) + return 0; + } if (base[I2C_STATUS] << 28) return 0; @@ -113,7 +136,7 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) { u8 tmp[4]; - if (size > 3) + if (size > 7) return 0; tmp[0] = y; diff --git a/source/soc/irq.c b/source/soc/irq.c new file mode 100644 index 0000000..627976d --- /dev/null +++ b/source/soc/irq.c @@ -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 . + */ + +#include + +#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--; + } +*/ +} diff --git a/source/soc/irq.h b/source/soc/irq.h new file mode 100644 index 0000000..c77d980 --- /dev/null +++ b/source/soc/irq.h @@ -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 . + */ + +#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 \ No newline at end of file diff --git a/source/soc/pinmux.h b/source/soc/pinmux.h index bb4ecb1..ca57584 100644 --- a/source/soc/pinmux.h +++ b/source/soc/pinmux.h @@ -62,6 +62,7 @@ #define PINMUX_AUX_LCD_BL_PWM 0x1FC #define PINMUX_AUX_LCD_BL_EN 0x200 #define PINMUX_AUX_LCD_RST 0x204 +#define PINMUX_AUX_LCD_GPIO1 0x208 #define PINMUX_AUX_LCD_GPIO2 0x20C #define PINMUX_AUX_TOUCH_INT 0x220 #define PINMUX_AUX_MOTION_INT 0x224 diff --git a/source/soc/pmc.h b/source/soc/pmc.h index 8cd9161..7df7922 100644 --- a/source/soc/pmc.h +++ b/source/soc/pmc.h @@ -25,13 +25,23 @@ #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #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 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_SCRATCH20 0xA0 #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 APBDEV_PMC_DDR_PWR 0xE8 +#define APBDEV_PMC_USB_AO 0xF0 #define APBDEV_PMC_CRYPTO_OP 0xF4 #define PMC_CRYPTO_OP_SE_ENABLE 0 #define PMC_CRYPTO_OP_SE_DISABLE 1 @@ -39,6 +49,8 @@ #define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 #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_IO_DPD_REQ 0x1B8 #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 diff --git a/source/soc/t210.h b/source/soc/t210.h index 85e42f4..b45ef2a 100644 --- a/source/soc/t210.h +++ b/source/soc/t210.h @@ -28,9 +28,11 @@ #define VIC_BASE 0x54340000 #define TSEC_BASE 0x54500000 #define SOR1_BASE 0x54580000 +#define ICTLR_BASE 0x60004000 #define TMR_BASE 0x60005000 #define CLOCK_BASE 0x60006000 #define FLOW_CTLR_BASE 0x60007000 +#define AHBDMA_BASE 0x60008000 #define SYSREG_BASE 0x6000C000 #define SB_BASE (SYSREG_BASE + 0x200) #define GPIO_BASE 0x6000D000 @@ -44,6 +46,7 @@ #define GPIO_8_BASE (GPIO_BASE + 0x700) #define EXCP_VEC_BASE 0x6000F000 #define IPATCH_BASE 0x6001DC00 +#define APBDMA_BASE 0x60020000 #define APB_MISC_BASE 0x70000000 #define PINMUX_AUX_BASE 0x70003000 #define UART_BASE 0x70006000 @@ -56,10 +59,16 @@ #define SE_BASE 0x70012000 #define MC_BASE 0x70019000 #define EMC_BASE 0x7001B000 +#define EMC0_BASE 0x7001E000 +#define EMC1_BASE 0x7001F000 #define MIPI_CAL_BASE 0x700E3000 #define CL_DVFS_BASE 0x70110000 #define I2S_BASE 0x702D1000 +#define ADMA_BASE 0x702E2000 #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)) @@ -70,10 +79,12 @@ #define VIC(off) _REG(VIC_BASE, off) #define TSEC(off) _REG(TSEC_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 CLOCK(off) _REG(CLOCK_BASE, off) #define FLOW_CTLR(off) _REG(FLOW_CTLR_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 GPIO(off) _REG(GPIO_BASE, off) #define GPIO_1(off) _REG(GPIO_1_BASE, off) @@ -96,9 +107,14 @@ #define SE(off) _REG(SE_BASE, off) #define MC(off) _REG(MC_BASE, off) #define EMC(off) _REG(EMC_BASE, off) +#define EMC_CH0(off) _REG(EMC0_BASE, off) +#define EMC_CH1(off) _REG(EMC1_BASE, off) #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 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) /* HOST1X registers. */ @@ -116,13 +132,40 @@ #define EVP_COP_RSVD_VECTOR 0x214 #define EVP_COP_IRQ_VECTOR 0x218 #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. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_PINMUX_GLOBAL 0x40 #define APB_MISC_GP_HIDREV 0x804 +#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #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_PUPD_CFGPADCTRL 0xABC #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 @@ -170,9 +213,14 @@ /*! TMR registers. */ #define TIMERUS_CNTR_1US (0x10 + 0x0) #define TIMERUS_USEC_CFG (0x10 + 0x4) +#define TIMER_TMR8_TMR_PTV 0x78 #define TIMER_TMR9_TMR_PTV 0x80 -#define TIMER_EN (1 << 31) -#define TIMER_PER_EN (1 << 30) +#define TIMER_EN (1 << 31) +#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_SRC(TMR) (TMR & 0xF) #define TIMER_PER(PER) ((PER & 0xFF) << 4) @@ -210,13 +258,15 @@ /*! Flow controller registers. */ #define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define HALT_COP_SEC (1 << 23) -#define HALT_COP_MSEC (1 << 24) -#define HALT_COP_USEC (1 << 25) -#define HALT_COP_JTAG (1 << 28) -#define HALT_COP_WAIT_EVENT (1 << 30) -#define HALT_COP_WAIT_IRQ (1 << 31) -#define HALT_COP_MAX_CNT 0xFF +#define HALT_COP_GIC_IRQ (1 << 9) +#define HALT_COP_LIC_IRQ (1 << 11) +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_STOP_UNTIL_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF #define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 #define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 #define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C @@ -228,4 +278,9 @@ #define FLOW_CTLR_RAM_REPAIR 0x40 #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 diff --git a/source/storage/emummc.c b/source/storage/emummc.c index a07d9ed..eea93e5 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 CTCaer + * 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, @@ -24,17 +24,12 @@ #include "../gfx/gfx.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" +#include "../storage/nx_sd.h" #include "../utils/list.h" #include "../utils/types.h" -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; - extern hekate_config h_cfg; - -extern bool sd_mount(); -extern void sd_unmount(); +emummc_cfg_t emu_cfg; bool emummc_load_cfg() { @@ -47,7 +42,8 @@ bool emummc_load_cfg() emu_cfg.file_based_part_size = 0; emu_cfg.active_part = 0; emu_cfg.fs_ver = 0; - emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + if (!emu_cfg.emummc_file_based_path) + emu_cfg.emummc_file_based_path = (char *)malloc(0x80); LIST_INIT(ini_sections); if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) @@ -94,18 +90,14 @@ static int emummc_raw_get_part_off(int part_idx) return 2; } - int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) { FILINFO fno; - if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); + if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + return 2; - goto out; - } if (h_cfg.emummc_force_disable) - return 1; + return 0; emu_cfg.active_part = 0; if (!sd_mount()) @@ -131,10 +123,11 @@ int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) } emu_cfg.file_based_part_size = fno.fsize >> 9; } - return 1; + + return 0; out: - return 0; + return 1; } int emummc_storage_end(sdmmc_storage_t *storage) diff --git a/source/storage/emummc.h b/source/storage/emummc.h index 635332f..0103841 100644 --- a/source/storage/emummc.h +++ b/source/storage/emummc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 CTCaer + * 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, @@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t int fs_ver; } emummc_cfg_t; -emummc_cfg_t emu_cfg; +extern emummc_cfg_t emu_cfg; bool emummc_load_cfg(); int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); diff --git a/source/storage/mbr_gpt.h b/source/storage/mbr_gpt.h new file mode 100644 index 0000000..923b6d2 --- /dev/null +++ b/source/storage/mbr_gpt.h @@ -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 . + */ + +#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[440]; + 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 diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index 2cae846..f5765a1 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -16,6 +16,7 @@ #include +#include "mbr_gpt.h" #include "nx_emmc.h" #include "emummc.h" #include "../mem/heap.h" @@ -23,28 +24,31 @@ 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 < hdr->num_part_ents; i++) + for (u32 i = 0; i < gpt_buf->header.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); - part->lba_start = ent->lba_start; - part->lba_end = ent->lba_end; - part->attrs = ent->attrs; + + if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba) + continue; + + 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. - for (u32 i = 0; i < 36; i++) - part->name[i] = ent->name[i]; - part->name[36] = 0; + for (u32 j = 0; j < 36; j++) + part->name[j] = gpt_buf->entries[i].name[j]; + part->name[35] = 0; list_append(gpt, &part->link); } - free(buf); + free(gpt_buf); } void nx_emmc_gpt_free(link_t *gpt) diff --git a/source/storage/nx_emmc.h b/source/storage/nx_emmc.h index 753d5aa..19bc1ca 100644 --- a/source/storage/nx_emmc.h +++ b/source/storage/nx_emmc.h @@ -17,38 +17,9 @@ #ifndef _NX_EMMC_H_ #define _NX_EMMC_H_ +#include "sdmmc.h" #include "../utils/types.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_NUM_BLOCKS 33 @@ -56,6 +27,7 @@ typedef struct _gpt_header_t typedef struct _emmc_part_t { + u32 index; u32 lba_start; u32 lba_end; u64 attrs; diff --git a/source/storage/nx_sd.c b/source/storage/nx_sd.c new file mode 100644 index 0000000..0a791ad --- /dev/null +++ b/source/storage/nx_sd.c @@ -0,0 +1,184 @@ +/* + * 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 . + */ + +#include "nx_sd.h" +#include "sdmmc.h" +#include "sdmmc_driver.h" +#include "../gfx/gfx.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" + +static bool sd_mounted = false; +static u32 sd_mode = SD_UHS_SDR82; + + +sdmmc_t sd_sdmmc; +sdmmc_storage_t sd_storage; +FATFS sd_fs; + +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; + + int res = !sd_initialize(false); + + 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; + } +} + +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; +} diff --git a/source/storage/nx_sd.h b/source/storage/nx_sd.h new file mode 100644 index 0000000..22e5f3b --- /dev/null +++ b/source/storage/nx_sd.h @@ -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 . + */ + +#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, +}; + +extern sdmmc_t sd_sdmmc; +extern sdmmc_storage_t sd_storage; +extern 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 \ No newline at end of file diff --git a/source/storage/sd.h b/source/storage/sd.h index fafd322..3ecfc07 100644 --- a/source/storage/sd.h +++ b/source/storage/sd.h @@ -106,6 +106,11 @@ #define SD_SET_CURRENT_LIMIT_600 2 #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 */ diff --git a/source/storage/sdmmc.c b/source/storage/sdmmc.c index d75e609..902d0ca 100644 --- a/source/storage/sdmmc.c +++ b/source/storage/sdmmc.c @@ -18,6 +18,7 @@ #include #include "sdmmc.h" #include "mmc.h" +#include "nx_sd.h" #include "sd.h" #include "../../common/memory_map.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) { + u32 tmp = 0; 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_req_t reqbuf; reqbuf.buf = buf; reqbuf.num_sectors = num_sectors; 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)) { - u32 tmp = 0; sdmmc_stop_transmission(storage->sdmmc, &tmp); _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) { u8 *bbuf = (u8 *)buf; - + bool first_reinit = false; while (num_sectors) { u32 blkcnt = 0; - //Retry 9 times on error. - u32 retries = 10; + // Retry 5 times if failed. + u32 retries = 5; do { +reinit_try: if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) goto out; else retries--; - msleep(100); + msleep(50); } 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; -out:; +out: DPRINTF("readwrite: %08X\n", blkcnt); sector += 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) { - 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) { - 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)) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 2)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52)) return 0; 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))) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 3)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200)) 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; 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)) return 0; - sdmmc_get_venclkctl(storage->sdmmc); + sdmmc_set_tap_value(storage->sdmmc); if (!_mmc_storage_enable_HS(storage, 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))) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 4)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400)) return 0; 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) { - //TODO: this should be a config item. - // --v - if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8) + if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8) goto out; if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && - card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4) + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400) return _mmc_storage_enable_HS400(storage); if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 && 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); -out:; +out: if (card_type & EXT_CSD_CARD_TYPE_HS_52) 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); } -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)); storage->sdmmc = sdmmc; 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; DPRINTF("[MMC] after init\n"); @@ -520,7 +559,7 @@ DPRINTF("[MMC] set relative addr\n"); DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); - if (!sdmmc_setup_clock(storage->sdmmc, 1)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26)) return 0; DPRINTF("[MMC] after setup clock\n"); @@ -544,35 +583,27 @@ DPRINTF("[MMC] set blocklen to 512\n"); return 0; DPRINTF("[MMC] switched buswidth\n"); - u8 *ext_csd = (u8 *)malloc(512); - if (!_mmc_storage_get_ext_csd(storage, ext_csd)) - { - free(ext_csd); + if (!_mmc_storage_get_ext_csd(storage, (u8 *)SDMMC_UPPER_BUFFER)) return 0; - } - free(ext_csd); DPRINTF("[MMC] got ext_csd\n"); + _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd //gfx_hexdump(0, ext_csd, 512); /* 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(). 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); DPRINTF("[MMC] BKOPS enabled\n"); } - else - { -DPRINTF("[MMC] BKOPS disabled\n"); - } if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; 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; } @@ -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) storage->has_sector_access = 1; + // Check if card supports 1.8V signaling. if (cond & SD_ROCR_S18A && supports_low_voltage) { //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); } -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); - while (pwr > 0) + if (((buf[15] >> 4) & 0x0F) == pwr) { - pwr--; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - if (((buf[15] >> 4) & 0x0F) == pwr) + switch (pwr) + { + case SD_SET_CURRENT_LIMIT_800: +DPRINTF("[SD] power limit raised to 800mA\n"); break; - } - - switch (pwr) - { - case SD_SET_CURRENT_LIMIT_800: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - case SD_SET_CURRENT_LIMIT_600: + case SD_SET_CURRENT_LIMIT_600: DPRINTF("[SD] power limit raised to 600mA\n"); - break; - case SD_SET_CURRENT_LIMIT_400: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - default: - case SD_SET_CURRENT_LIMIT_200: + break; + case SD_SET_CURRENT_LIMIT_400: +DPRINTF("[SD] power limit raised to 400mA\n"); + break; + default: + case SD_SET_CURRENT_LIMIT_200: 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)) 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; if (type_out != hs_type) 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)) return 0; if (type_out != (buf[16] & 0xF)) 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) { - // 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) return 0; @@ -870,32 +908,55 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) return 0; //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; switch (type) { - case 11: // SDR104. + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: // 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; 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; } - case 10: // SDR50. - if (buf[13] & SD_MODE_UHS_SDR50) + case SDHCI_TIMING_UHS_SDR50: + if (access_mode & SD_MODE_UHS_SDR50) { - type = 10; + type = SDHCI_TIMING_UHS_SDR50; hs_type = UHS_SDR50_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } - case 8: // SDR12. - if (!(buf[13] & SD_MODE_UHS_SDR12)) + case SDHCI_TIMING_UHS_SDR25: + 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; - type = 8; + type = SDHCI_TIMING_UHS_SDR12; hs_type = UHS_SDR12_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR12\n"); 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)) return 0; -DPRINTF("[SD] SD card accepted UHS\n"); +DPRINTF("[SD] card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; DPRINTF("[SD] setup clock\n"); - if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) + if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; DPRINTF("[SD] config tuning\n"); 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)) return 0; //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; - if (!_sd_storage_enable_highspeed(storage, 1, buf)) + if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf)) return 0; if (!_sdmmc_storage_check_status(storage)) 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) @@ -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() { 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); } -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; 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)); 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; DPRINTF("[SD] after init\n"); @@ -1088,7 +1173,9 @@ DPRINTF("[SD] went to idle state\n"); return 0; 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; 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 (!sdmmc_setup_clock(storage->sdmmc, 6)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12)) return 0; 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)) return 0; 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)) return 0; 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. 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)); 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; DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); - if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200)) return 0; DPRINTF("[gc] after tuning\n"); - sdmmc_sd_clock_ctrl(sdmmc, 1); + sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE); return 1; } diff --git a/source/storage/sdmmc.h b/source/storage/sdmmc.h index c8b8f96..aacc26a 100644 --- a/source/storage/sdmmc.h +++ b/source/storage/sdmmc.h @@ -21,7 +21,17 @@ #include "../utils/types.h" #include "sdmmc_driver.h" -u32 sd_power_cycle_time_start; +extern 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 { @@ -107,10 +117,10 @@ typedef struct _sdmmc_storage_t 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_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); 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); #endif diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 57d20f9..8e32f5d 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -32,6 +32,8 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) +u32 sd_power_cycle_time_start; + /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -40,44 +42,37 @@ static const u32 _sdmmc_bases[4] = { 0x700B0600, }; -int sdmmc_get_voltage(sdmmc_t *sdmmc) +int sdmmc_get_io_power(sdmmc_t *sdmmc) { u32 p = sdmmc->regs->pwrcon; - if (!(p & TEGRA_MMC_PWRCTL_SD_BUS_POWER)) + if (!(p & SDHCI_POWER_ON)) return SDMMC_POWER_OFF; - if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8) + if (p & SDHCI_POWER_180) return SDMMC_POWER_1_8; - if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3) + if (p & SDHCI_POWER_330) return SDMMC_POWER_3_3; return -1; } -static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) +static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power) { - u8 pwr = 0; - switch (power) { case SDMMC_POWER_OFF: - sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; + sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON; break; case SDMMC_POWER_1_8: - sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; - pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; + sdmmc->regs->pwrcon = SDHCI_POWER_180; break; case SDMMC_POWER_3_3: - sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; - pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; + sdmmc->regs->pwrcon = SDHCI_POWER_330; break; default: return 0; } if (power != SDMMC_POWER_OFF) - { - pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; - sdmmc->regs->pwrcon = pwr; - } + sdmmc->regs->pwrcon |= SDHCI_POWER_ON; return 1; } @@ -85,40 +80,44 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) { u32 h = sdmmc->regs->hostctl; - if (h & TEGRA_MMC_HOSTCTL_8BIT) + if (h & SDHCI_CTRL_8BITBUS) return SDMMC_BUS_WIDTH_8; - if (h & TEGRA_MMC_HOSTCTL_4BIT) + if (h & SDHCI_CTRL_4BITBUS) return SDMMC_BUS_WIDTH_4; return SDMMC_BUS_WIDTH_1; } void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) { + u32 host_control = sdmmc->regs->hostctl & ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS); + if (bus_width == SDMMC_BUS_WIDTH_1) - sdmmc->regs->hostctl &= ~(TEGRA_MMC_HOSTCTL_4BIT | TEGRA_MMC_HOSTCTL_8BIT); + sdmmc->regs->hostctl = host_control; else if (bus_width == SDMMC_BUS_WIDTH_4) - { - sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_4BIT; - sdmmc->regs->hostctl &= ~TEGRA_MMC_HOSTCTL_8BIT; - } + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_4BITBUS; else if (bus_width == SDMMC_BUS_WIDTH_8) - sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_8BIT; + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; } -void sdmmc_get_venclkctl(sdmmc_t *sdmmc) +void sdmmc_set_tap_value(sdmmc_t *sdmmc) { sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; sdmmc->venclkctl_set = 1; } -static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) +static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) { + const u32 dqs_trim_val = 0x28; + const u32 tap_values[] = { 4, 0, 3, 0 }; + u32 tap_val = 0; - if (id == 4) - sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800; - sdmmc->regs->ventunctl0 &= 0xFFFDFFFF; - if (id == 4) + if (type == SDHCI_TIMING_MMC_HS400) + sdmmc->regs->vencapover = (sdmmc->regs->vencapover & 0xFFFFC0FF) | (dqs_trim_val << 8); + + sdmmc->regs->ventunctl0 &= ~TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; + + if (type == SDHCI_TIMING_MMC_HS400) { if (!sdmmc->venclkctl_set) return 0; @@ -127,7 +126,6 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) } else { - static const u32 tap_values[] = { 4, 0, 3, 0 }; tap_val = tap_values[sdmmc->id]; } sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); @@ -145,163 +143,250 @@ static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) _sdmmc_get_clkcon(sdmmc); switch (sdmmc->id) { - case SDMMC_1: + case SDMMC_1: // 33 Ohm 2X Driver. if (power == SDMMC_POWER_OFF) break; + u32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF; if (power == SDMMC_POWER_1_8) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. else if (power == SDMMC_POWER_3_3) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. break; - case SDMMC_4: - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040; + case SDMMC_2: + case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; break; } - //TODO: load standard values for other controllers, can depend on power. } -static int _sdmmc_wait_type4(sdmmc_t *sdmmc) +static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) { - int res = 1, should_disable_sd_clock = 0; - - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + bool should_enable_sd_clock = false; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) { - should_disable_sd_clock = 1; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + should_enable_sd_clock = true; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } - sdmmc->regs->vendllcal |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); + // Enable E_INPUT power. + if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD)) + { + sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; + _sdmmc_get_clkcon(sdmmc); + usleep(1); + } - u32 timeout = get_tmr_ms() + 5; - while (sdmmc->regs->vendllcal & 0x80000000) + // Enable auto calibration and start auto configuration. + sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START; + _sdmmc_get_clkcon(sdmmc); + usleep(2); + + u32 timeout = get_tmr_ms() + 10; + while (sdmmc->regs->autocalsts & TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE) { if (get_tmr_ms() > timeout) { - res = 0; + timeout = 0; // Set timeout to 0 if we timed out. + break; + } + } +/* + // Check if PU results are inside limits. + // SDMMC1: CZ pads - 7-bit PU. SDMMC2/4: LV_CZ pads - 5-bit PU. + u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x7F; + switch (sdmmc->id) + { + case SDMMC_1: + if (!autocal_pu_status || autocal_pu_status == 0x7F) + timeout = 0; + break; + case SDMMC_2: + case SDMMC_4: + autocal_pu_status &= 0x1F; + if (!autocal_pu_status || autocal_pu_status == 0x1F) + timeout = 0; + break; + } +*/ + // In case auto calibration fails, we load suggested standard values. + if (!timeout) + { + _sdmmc_pad_config_fallback(sdmmc, power); + sdmmc->regs->autocalcfg &= ~TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE; + } + + // Disable E_INPUT to conserve power. + sdmmc->regs->sdmemcmppadctl &= ~TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; + + if(should_enable_sd_clock) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; +} + +static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) +{ + int result = 1, should_disable_sd_clock = 0; + + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + } + + sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE; + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_ms() + 5; + while (sdmmc->regs->vendllcalcfg & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE) + { + if (get_tmr_ms() > timeout) + { + result = 0; goto out; } } timeout = get_tmr_ms() + 10; - while (sdmmc->regs->dllcfgstatus & 0x80000000) + while (sdmmc->regs->vendllcalcfgsts & TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE) { if (get_tmr_ms() > timeout) { - res = 0; + result = 0; goto out; } } out:; if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - return res; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + return result; +} + +static void _sdmmc_reset(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA; + _sdmmc_get_clkcon(sdmmc); + u32 timeout = get_tmr_ms() + 2000; + while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout) + ; } int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) { // Disable the SD clock if it was enabled, and reenable it later. bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) { should_enable_sd_clock = true; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } - _sdmmc_config_ven_ceata_clk(sdmmc, type); + _sdmmc_config_tap_val(sdmmc, type); + + _sdmmc_reset(sdmmc); switch (type) { - case 0: - case 1: - case 5: - case 6: - sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ? - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; + case SDHCI_TIMING_MMC_ID: + case SDHCI_TIMING_MMC_LS26: + case SDHCI_TIMING_SD_ID: + case SDHCI_TIMING_SD_DS12: + sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; - case 2: - case 7: - sdmmc->regs->hostctl |= 4; - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; + case SDHCI_TIMING_MMC_HS52: + case SDHCI_TIMING_SD_HS25: + sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; - case 3: - case 11: - case 13: - case 14: + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104. + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + case SDHCI_TIMING_UHS_DDR50: + case SDHCI_TIMING_MMC_DDR52: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; - case 4: + case SDHCI_TIMING_MMC_HS400: // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; - case 8: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; + case SDHCI_TIMING_UHS_SDR25: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; - case 10: - // T210 Errata for SDR50, the host must be set to SDR104. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; + case SDHCI_TIMING_UHS_SDR12: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; } _sdmmc_get_clkcon(sdmmc); - u32 tmp; + u32 clock; u16 divisor; - clock_sdmmc_get_card_clock_div(&tmp, &divisor, type); - clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp); - sdmmc->divisor = (tmp + divisor - 1) / divisor; + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); + clock_sdmmc_config_clock_source(&clock, sdmmc->id, clock); + sdmmc->divisor = (clock + divisor - 1) / divisor; //if divisor != 1 && divisor << 31 -> error u16 div = divisor >> 1; divisor = 0; if (div > 0xFF) - divisor = div >> 8; - sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6); + divisor = div >> SDHCI_DIVIDER_SHIFT; + + sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK)) + | (div << SDHCI_DIVIDER_SHIFT) | (divisor << SDHCI_DIVIDER_HI_SHIFT); // Enable the SD clock again. if (should_enable_sd_clock) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; - if (type == 4) - return _sdmmc_wait_type4(sdmmc); + if (type == SDHCI_TIMING_MMC_HS400) + return _sdmmc_dll_cal_execute(sdmmc); return 1; } -static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc) +static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc) { - if (!sdmmc->no_sd) + // Recalibrate conditionally. + if ((sdmmc->id == SDMMC_1) && !sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + if (!sdmmc->auto_cal_enabled) { - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } - sdmmc->sd_clock_enabled = 1; + sdmmc->card_clock_enabled = 1; } static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) { - sdmmc->sd_clock_enabled = 0; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->card_clock_enabled = 0; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } -void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd) +void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable) { - sdmmc->no_sd = no_sd; - if (no_sd) + // Recalibrate periodically for SDMMC1. + if ((sdmmc->id == SDMMC_1) && !auto_cal_enable && sdmmc->card_clock_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + sdmmc->auto_cal_enabled = auto_cal_enable; + if (auto_cal_enable) { - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) return; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return; } - if (sdmmc->sd_clock_enabled) - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + + if (sdmmc->card_clock_enabled) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) @@ -383,22 +468,12 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) return 1; } -static void _sdmmc_reset(sdmmc_t *sdmmc) -{ - sdmmc->regs->swrst |= - TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE; - _sdmmc_get_clkcon(sdmmc); - u32 timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->swrst << 29 >> 30 && get_tmr_ms() < timeout) - ; -} - -static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) +static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) { _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) // CMD inhibit. + while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -408,7 +483,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) if (wait_dat) { timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) // DAT inhibit. + while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -419,12 +494,12 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) return 1; } -static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc) +static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc) { _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level. + while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK)) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -442,21 +517,21 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) return 0; break; case SDMMC_BUS_WIDTH_4: - sdmmc->regs->blksize = 0x40; + sdmmc->regs->blksize = 64; break; case SDMMC_BUS_WIDTH_8: - sdmmc->regs->blksize = 0x80; + sdmmc->regs->blksize = 128; break; } sdmmc->regs->blkcnt = 1; - sdmmc->regs->trnmod = TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; + sdmmc->regs->trnmod = SDHCI_TRNS_READ; return 1; } -static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) +static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) { u16 cmdflags = 0; - + switch (cmd->rsp_type) { case SDMMC_RSP_TYPE_0: @@ -465,20 +540,15 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr case SDMMC_RSP_TYPE_4: case SDMMC_RSP_TYPE_5: if (cmd->check_busy) - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY | - TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + cmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; else - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 | - TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; break; case SDMMC_RSP_TYPE_2: - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC; break; case SDMMC_RSP_TYPE_3: - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48; + cmdflags = SDHCI_CMD_RESP_LEN48; break; default: return 0; @@ -486,52 +556,52 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr } if (is_data_present) - cmdflags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER; + cmdflags |= SDHCI_CMD_DATA; sdmmc->regs->argument = cmd->arg; sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags; return 1; } -static void _sdmmc_parse_cmd_48(sdmmc_t *sdmmc, u32 cmd) +static void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd) { sdmmc_cmd_t cmdbuf; cmdbuf.cmd = cmd; cmdbuf.arg = 0; cmdbuf.rsp_type = SDMMC_RSP_TYPE_1; cmdbuf.check_busy = 0; - _sdmmc_parse_cmdbuf(sdmmc, &cmdbuf, true); + _sdmmc_send_cmd(sdmmc, &cmdbuf, true); } -static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) +static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) { - if (sdmmc->no_sd) + if (sdmmc->auto_cal_enabled) return 0; - if (!_sdmmc_wait_prnsts_type0(sdmmc, 1)) + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true)) return 0; _sdmmc_setup_read_small_block(sdmmc); - sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY; + sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL; sdmmc->regs->norintsts = sdmmc->regs->norintsts; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; - _sdmmc_parse_cmd_48(sdmmc, cmd); + _sdmmc_send_tuning_cmd(sdmmc, cmd); _sdmmc_get_clkcon(sdmmc); usleep(1); _sdmmc_reset(sdmmc); - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_us() + 5000; while (get_tmr_us() < timeout) { - if (sdmmc->regs->norintsts & 0x20) + if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL) { - sdmmc->regs->norintsts = 0x20; - sdmmc->regs->norintstsen &= 0xFFDF; + sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL; + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; _sdmmc_get_clkcon(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 1; @@ -540,44 +610,49 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) _sdmmc_reset(sdmmc); - sdmmc->regs->norintstsen &= 0xFFDF; + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; _sdmmc_get_clkcon(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 0; } -int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) +int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd) { u32 max = 0, flag = 0; - sdmmc->regs->field_1C4 = 0; switch (type) { - case 3: - case 4: - case 11: - max = 0x80; - flag = 0x4000; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + max = 128; + flag = (2 << 13); // 128 iterations. break; - case 10: - case 13: - case 14: - max = 0x100; - flag = 0x8000; + case SDHCI_TIMING_UHS_SDR50: + case SDHCI_TIMING_UHS_DDR50: + case SDHCI_TIMING_MMC_DDR52: + max = 256; + flag = (4 << 13); // 256 iterations. break; + case SDHCI_TIMING_UHS_SDR12: + case SDHCI_TIMING_UHS_SDR25: + return 1; default: return 0; } + sdmmc->regs->ventunctl1 = 0; // step_size 1. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier. - sdmmc->regs->ventunctl0 |= 0x20000; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier. + sdmmc->regs->ventunctl0 |= TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; for (u32 i = 0; i < max; i++) { - _sdmmc_config_tuning_once(sdmmc, cmd); + _sdmmc_tuning_execute_once(sdmmc, cmd); if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) break; } @@ -591,24 +666,24 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) { //Enable internal clock and wait till it is stable. - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN; _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) + while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE)) { if (get_tmr_ms() > timeout) return 0; } sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT; + sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE; sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; - if (!(sdmmc->regs->capareg & 0x10000000)) + if (!(sdmmc->regs->capareg & SDHCI_CAN_64BIT)) return 0; sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; - sdmmc->regs->hostctl &= 0xE7; + sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK; sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE; return 1; @@ -645,60 +720,22 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) break; } - sdmmc->regs->autocalcfg = (((sdmmc->regs->autocalcfg & 0xFFFF80FF) | (off_pd << 8)) >> 7 << 7) | off_pu; + sdmmc->regs->autocalcfg = (sdmmc->regs->autocalcfg & 0xFFFF8080) | (off_pd << 8) | off_pu; return 1; } -static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) -{ - bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = true; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000)) - { - sdmmc->regs->sdmemcmppadctl |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - } - - sdmmc->regs->autocalcfg |= 0xA0000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - - u32 timeout = get_tmr_ms() + 10; - while (sdmmc->regs->autocalcfg & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - // In case autocalibration fails, we load suggested standard values. - _sdmmc_pad_config_fallback(sdmmc, power); - sdmmc->regs->autocalcfg &= 0xDFFFFFFF; - break; - } - } - - sdmmc->regs->sdmemcmppadctl &= 0x7FFFFFFF; - - if(should_enable_sd_clock) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; -} - static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) { - sdmmc->regs->norintstsen |= 0xB; - sdmmc->regs->errintstsen |= 0x17F; + sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; + sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; sdmmc->regs->norintsts = sdmmc->regs->norintsts; sdmmc->regs->errintsts = sdmmc->regs->errintsts; } static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) { - sdmmc->regs->errintstsen &= 0xFE80; - sdmmc->regs->norintstsen &= 0xFFF4; + sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; + sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); } static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) @@ -706,13 +743,13 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) u16 norintsts = sdmmc->regs->norintsts; u16 errintsts = sdmmc->regs->errintsts; - DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); +DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); if (pout) *pout = norintsts; // Check for error interrupt. - if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) + if (norintsts & SDHCI_INT_ERROR) { sdmmc->regs->errintsts = errintsts; return SDMMC_MASKINT_ERROR; @@ -726,17 +763,17 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) return SDMMC_MASKINT_NOERROR; } -static int _sdmmc_wait_request(sdmmc_t *sdmmc) +static int _sdmmc_wait_response(sdmmc_t *sdmmc) { _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while (1) + while (true) { - int res = _sdmmc_check_mask_interrupt(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE); - if (res == SDMMC_MASKINT_MASKED) + int result = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE); + if (result == SDMMC_MASKINT_MASKED) break; - if (res != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) + if (result != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); return 0; @@ -750,7 +787,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) { sdmmc_cmd_t cmd; - if (!_sdmmc_wait_prnsts_type0(sdmmc, 0)) + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, false)) return 0; _sdmmc_enable_interrupts(sdmmc); @@ -760,40 +797,44 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) cmd.rsp_type = SDMMC_RSP_TYPE_1; cmd.check_busy = 1; - _sdmmc_parse_cmdbuf(sdmmc, &cmd, false); + _sdmmc_send_cmd(sdmmc, &cmd, false); - int res = _sdmmc_wait_request(sdmmc); + int result = _sdmmc_wait_response(sdmmc); _sdmmc_mask_interrupts(sdmmc); - if (!res) + if (!result) return 0; _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); - return _sdmmc_wait_prnsts_type1(sdmmc); + return _sdmmc_wait_card_busy(sdmmc); } int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) { - if (!sdmmc->sd_clock_enabled) + if (!sdmmc->card_clock_enabled) return 0; + // Recalibrate periodically for SDMMC1. + if ((sdmmc->id == SDMMC_1) && sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + bool should_disable_sd_clock = false; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) { should_disable_sd_clock = true; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_get_clkcon(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } - int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); + int result = _sdmmc_stop_transmission_inner(sdmmc, rsp); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; - return res; + return result; } static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) @@ -807,7 +848,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) u32 admaaddr = (u32)req->buf; // Check alignment. - if (admaaddr << 29) + if (admaaddr & 7) return 0; sdmmc->regs->admaaddr = admaaddr; @@ -815,22 +856,20 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000; - sdmmc->regs->blksize = req->blksize | 0x7000; + sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out). sdmmc->regs->blkcnt = blkcnt; if (blkcnt_out) *blkcnt_out = blkcnt; - u32 trnmode = TEGRA_MMC_TRNMOD_DMA_ENABLE; + u32 trnmode = SDHCI_TRNS_DMA; if (req->is_multi_block) - trnmode = TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT | - TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE | - TEGRA_MMC_TRNMOD_DMA_ENABLE; + trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA; if (!req->is_write) - trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; + trnmode |= SDHCI_TRNS_READ; if (req->is_auto_cmd12) - trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12; + sdmmc->regs->trnmod = trnmode; return 1; @@ -845,20 +884,19 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) u32 timeout = get_tmr_ms() + 1500; do { - int res = 0; - while (1) + int result = 0; + while (true) { u16 intr = 0; - res = _sdmmc_check_mask_interrupt(sdmmc, &intr, - TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT); - if (res < 0) + result = _sdmmc_check_mask_interrupt(sdmmc, &intr, + SDHCI_INT_DATA_END | SDHCI_INT_DMA_END); + if (result < 0) break; - if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) - { - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + if (intr & SDHCI_INT_DATA_END) return 1; // Transfer complete. - } - if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) + + if (intr & SDHCI_INT_DMA_END) { // Update DMA. sdmmc->regs->admaaddr = sdmmc->dma_addr_next; @@ -866,8 +904,9 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) sdmmc->dma_addr_next += 0x80000; } } - if (res != SDMMC_MASKINT_NOERROR) + if (result != SDMMC_MASKINT_NOERROR) { + DPRINTF("%08X!\n", result); _sdmmc_reset(sdmmc); return 0; } @@ -881,45 +920,72 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) { int has_req_or_check_busy = req || cmd->check_busy; - if (!_sdmmc_wait_prnsts_type0(sdmmc, has_req_or_check_busy)) + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy)) return 0; u32 blkcnt = 0; bool is_data_present = false; if (req) { - _sdmmc_config_dma(sdmmc, &blkcnt, req); - _sdmmc_enable_interrupts(sdmmc); + if (!_sdmmc_config_dma(sdmmc, &blkcnt, req)) + { + DPRINTF("SDMMC: DMA Wrong cfg!\n"); + return 0; + } + + // Flush cache before starting the transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + is_data_present = true; } else - { - _sdmmc_enable_interrupts(sdmmc); is_data_present = false; + + _sdmmc_enable_interrupts(sdmmc); + + if (!_sdmmc_send_cmd(sdmmc, cmd, is_data_present)) + { + DPRINTF("SDMMC: Wrong Response type %08X!\n", cmd->rsp_type); + return 0; } - _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); - - int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + int result = _sdmmc_wait_response(sdmmc); + if (!result) + { + DPRINTF("SDMMC: Transfer timeout!\n"); + } + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); - if (res) + if (result) { if (cmd->rsp_type) { sdmmc->expected_rsp_type = cmd->rsp_type; - _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); + result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); + if (!result) + { + DPRINTF("SDMMC: Unknown response %08X!\n", sdmmc->rsp[0]); + } + } + if (req && result) + { + result = _sdmmc_update_dma(sdmmc); + if (!result) + { + DPRINTF("SDMMC: DMA Update failed!\n"); + } } - if (req) - _sdmmc_update_dma(sdmmc); } _sdmmc_mask_interrupts(sdmmc); - if (res) + if (result) { if (req) { + // Flush cache after transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + if (blkcnt_out) *blkcnt_out = blkcnt; @@ -928,30 +994,42 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ } if (cmd->check_busy || req) - return _sdmmc_wait_prnsts_type1(sdmmc); + { + result = _sdmmc_wait_card_busy(sdmmc); + if (!result) + { + DPRINTF("SDMMC: Busy timeout!\n"); + } + return result; + } } - return res; + return result; +} + +bool sdmmc_get_sd_inserted() +{ + return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)); } static int _sdmmc_config_sdmmc1() { // Configure SD card detect. - PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //GPIO control, pull up. + PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up. APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); // Check if SD card is inserted. - if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) + if(!sdmmc_get_sd_inserted()) return 0; /* * Pinmux config: * DRV_TYPE = DRIVE_2X - * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) - * E_INPUT = ENABLE + * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) + * E_INPUT = ENABLE * TRISTATE = PASSTHROUGH * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK */ @@ -966,47 +1044,78 @@ static int _sdmmc_config_sdmmc1() PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; // Make sure the SDMMC1 controller is powered. - PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12); - // Assume 3.3V SD card voltage. - PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN; + usleep(1000); + PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN); + + // Inform IO pads that voltage is gonna be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; // Set enable SD card power. - PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down. + PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Pull down. gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); - usleep(1000); // Enable SD card power. max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); max77620_regulator_enable(REGULATOR_LDO2, 1); - usleep(1000); - // For good measure. - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; - + // Set pad slew codes to get good quality clock. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; usleep(1000); return 1; } -int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd) +static void _sdmmc_config_emmc(u32 id) { + switch (id) + { + case SDMMC_2: + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; + break; + case SDMMC_4: + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF; + // Set default pad cfg. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; + + // Enabled schmitt trigger. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; // Enable Schmitt trigger. + break; + } +} + +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable) +{ + const u32 trim_values[] = { 2, 8, 3, 8 }; + if (id > SDMMC_4) return 0; - if (id == SDMMC_1) - if (!_sdmmc_config_sdmmc1()) - return 0; - memset(sdmmc, 0, sizeof(sdmmc_t)); sdmmc->regs = (t210_sdmmc_t *)_sdmmc_bases[id]; sdmmc->id = id; sdmmc->clock_stopped = 1; + // Do specific SDMMC HW configuration. + switch (id) + { + case SDMMC_1: + if (!_sdmmc_config_sdmmc1()) + return 0; + break; + case SDMMC_2: + case SDMMC_4: + _sdmmc_config_emmc(id); + break; + } + if (clock_sdmmc_is_not_reset_and_enabled(id)) { _sdmmc_sd_clock_disable(sdmmc); @@ -1021,11 +1130,12 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n sdmmc->clock_stopped = 0; //TODO: make this skip-able. - sdmmc->regs->iospare |= 0x80000; - sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; - static const u32 trim_values[] = { 2, 8, 3, 8 }; - sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24); - sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7; + sdmmc->regs->iospare |= 0x80000; // Enable muxing. + sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; // Set Band Gap VREG to supply DLL. + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | (trim_values[sdmmc->id] << 24); + sdmmc->regs->sdmemcmppadctl = + (sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7; + if (!_sdmmc_autocal_config_offset(sdmmc, power)) return 0; @@ -1034,12 +1144,12 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n if (_sdmmc_enable_internal_clock(sdmmc)) { sdmmc_set_bus_width(sdmmc, bus_width); - _sdmmc_set_voltage(sdmmc, power); + _sdmmc_set_io_power(sdmmc, power); if (sdmmc_setup_clock(sdmmc, type)) { - sdmmc_sd_clock_ctrl(sdmmc, no_sd); - _sdmmc_sd_clock_enable(sdmmc); + sdmmc_card_clock_ctrl(sdmmc, auto_cal_enable); + _sdmmc_card_clock_enable(sdmmc); _sdmmc_get_clkcon(sdmmc); return 1; @@ -1056,14 +1166,18 @@ void sdmmc_end(sdmmc_t *sdmmc) { _sdmmc_sd_clock_disable(sdmmc); // Disable SDMMC power. - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. if (sdmmc->id == SDMMC_1) { gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); max77620_regulator_enable(REGULATOR_LDO2, 0); - sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. + + // Inform IO pads that next voltage might be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + + sd_power_cycle_time_start = get_tmr_ms(); // Some SanDisk U1 cards need 100ms for a power cycle. usleep(1000); // To power cycle, min 1ms without power is needed. } @@ -1083,29 +1197,29 @@ void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 che int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) { - if (!sdmmc->sd_clock_enabled) + if (!sdmmc->card_clock_enabled) return 0; // Recalibrate periodically for SDMMC1. - if (sdmmc->id == SDMMC_1 && sdmmc->no_sd) - _sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc)); + if (sdmmc->id == SDMMC_1 && sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); int should_disable_sd_clock = 0; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) { should_disable_sd_clock = 1; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_get_clkcon(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } - int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); + int result = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; - return res; + return result; } int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) @@ -1113,11 +1227,18 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) if(sdmmc->id != SDMMC_1) return 0; - if (!sdmmc_setup_clock(sdmmc, 8)) + if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12)) return 0; _sdmmc_get_clkcon(sdmmc); + // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); + usleep(300); + + // Inform IO pads that we switched to 1.8V. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN); + // Enable schmitt trigger for better duty cycle and low jitter clock. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; @@ -1126,18 +1247,16 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; - max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); - PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12); - _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8); _sdmmc_get_clkcon(sdmmc); - msleep(5); + msleep(5); // Wait minimum 5ms before turning on the card clock. + // Turn on SDCLK. if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_get_clkcon(sdmmc); usleep(1000); if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) diff --git a/source/storage/sdmmc_driver.h b/source/storage/sdmmc_driver.h index cf9b9e1..736faa8 100644 --- a/source/storage/sdmmc_driver.h +++ b/source/storage/sdmmc_driver.h @@ -1,5 +1,6 @@ /* * 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, @@ -49,24 +50,158 @@ #define SDMMC_MASKINT_NOERROR -1 #define SDMMC_MASKINT_ERROR -2 -/*! SDMMC host control 2 */ -#define SDHCI_CTRL_UHS_MASK 0xFFF8 -#define SDHCI_CTRL_VDD_330 0xFFF7 -#define SDHCI_CTRL_VDD_180 8 -#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 present state. */ +#define SDHCI_CMD_INHIBIT 0x1 +#define SDHCI_DATA_INHIBIT 0x2 +#define SDHCI_DOING_WRITE 0x100 +#define SDHCI_DOING_READ 0x200 +#define SDHCI_SPACE_AVAILABLE 0x400 +#define SDHCI_DATA_AVAILABLE 0x800 +#define SDHCI_CARD_PRESENT 0x10000 +#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. */ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 +#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. */ #define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) @@ -78,8 +213,8 @@ typedef struct _sdmmc_t u32 id; u32 divisor; u32 clock_stopped; - int no_sd; - int sd_clock_enabled; + int auto_cal_enabled; + int card_clock_enabled; int venclkctl_set; u32 venclkctl_tap; u32 expected_rsp_type; @@ -108,19 +243,20 @@ typedef struct _sdmmc_req_t int is_auto_cmd12; } sdmmc_req_t; -int sdmmc_get_voltage(sdmmc_t *sdmmc); -u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); +int sdmmc_get_io_power(sdmmc_t *sdmmc); +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); -void sdmmc_get_venclkctl(sdmmc_t *sdmmc); -int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); -void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd); -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_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); +void sdmmc_set_tap_value(sdmmc_t *sdmmc); +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); +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_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd); +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); +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_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_enable_low_voltage(sdmmc_t *sdmmc); +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); #endif diff --git a/source/storage/sdmmc_t210.h b/source/storage/sdmmc_t210.h index e11c3ff..eb17714 100644 --- a/source/storage/sdmmc_t210.h +++ b/source/storage/sdmmc_t210.h @@ -1,5 +1,6 @@ /* * 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, @@ -19,49 +20,14 @@ #include "../utils/types.h" -#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1 -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1 - -#define TEGRA_MMC_HOSTCTL_1BIT 0x00 -#define TEGRA_MMC_HOSTCTL_4BIT 0x02 -#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 +#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000 +#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000 +#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000 +#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000 +#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0 +#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000 +#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000 +#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000 typedef struct _t210_sdmmc_t { @@ -77,56 +43,66 @@ typedef struct _t210_sdmmc_t vu32 rspreg3; vu32 bdata; vu32 prnsts; - vu8 hostctl; - vu8 pwrcon; - vu8 blkgap; - vu8 wakcon; + vu8 hostctl; + vu8 pwrcon; + vu8 blkgap; + vu8 wakcon; vu16 clkcon; - vu8 timeoutcon; - vu8 swrst; + vu8 timeoutcon; + vu8 swrst; vu16 norintsts; vu16 errintsts; - vu16 norintstsen; - vu16 errintstsen; - vu16 norintsigen; - vu16 errintsigen; + vu16 norintstsen; // Enable irq status. + vu16 errintstsen; // Enable irq status. + vu16 norintsigen; // Enable irq signal to LIC/GIC. + vu16 errintsigen; // Enable irq signal to LIC/GIC. vu16 acmd12errsts; vu16 hostctl2; vu32 capareg; vu32 capareg_1; vu32 maxcurr; - vu8 res3[4]; + vu8 rsvd0[4]; // 4C-4F reserved for more max current. vu16 setacmd12err; vu16 setinterr; - vu8 admaerr; - vu8 res4[3]; + vu8 admaerr; + vu8 rsvd1[3]; // 55-57 reserved. vu32 admaaddr; vu32 admaaddr_hi; - vu8 res5[156]; - vu16 slotintstatus; + vu8 rsvd2[156]; // 60-FB reserved. + vu16 slotintsts; vu16 hcver; vu32 venclkctl; - vu32 venspictl; - vu32 venspiintsts; - vu32 venceatactl; + vu32 vensysswctl; + vu32 venerrintsts; + vu32 vencapover; vu32 venbootctl; vu32 venbootacktout; vu32 venbootdattout; vu32 vendebouncecnt; vu32 venmiscctl; - vu32 res6[34]; + vu32 maxcurrover; + vu32 maxcurrover_hi; + vu32 unk0[32]; // 0x12C vu32 veniotrimctl; - vu32 vendllcal; - vu8 res7[8]; - vu32 dllcfgstatus; + vu32 vendllcalcfg; + vu32 vendllctl0; + vu32 vendllctl1; + vu32 vendllcalcfgsts; vu32 ventunctl0; - vu32 field_1C4; - vu8 field_1C8[24]; + vu32 ventunctl1; + vu32 ventunsts0; + vu32 ventunsts1; + vu32 venclkgatehystcnt; + vu32 venpresetval0; + vu32 venpresetval1; + vu32 venpresetval2; vu32 sdmemcmppadctl; vu32 autocalcfg; vu32 autocalintval; vu32 autocalsts; vu32 iospare; + vu32 mcciffifoctl; + vu32 timeoutwcoal; } t210_sdmmc_t; #endif diff --git a/source/utils/types.h b/source/utils/types.h index 544e059..7a7d847 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -27,20 +27,20 @@ #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) -#define KB_FIRMWARE_VERSION_100_200 0 -#define KB_FIRMWARE_VERSION_300 1 -#define KB_FIRMWARE_VERSION_301 2 -#define KB_FIRMWARE_VERSION_400 3 -#define KB_FIRMWARE_VERSION_500 4 -#define KB_FIRMWARE_VERSION_600 5 -#define KB_FIRMWARE_VERSION_620 6 -#define KB_FIRMWARE_VERSION_700 7 -#define KB_FIRMWARE_VERSION_810 8 -#define KB_FIRMWARE_VERSION_900 9 -#define KB_FIRMWARE_VERSION_910 10 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 +// #define KB_FIRMWARE_VERSION_100_200 0 +// #define KB_FIRMWARE_VERSION_300 1 +// #define KB_FIRMWARE_VERSION_301 2 +// #define KB_FIRMWARE_VERSION_400 3 +// #define KB_FIRMWARE_VERSION_500 4 +// #define KB_FIRMWARE_VERSION_600 5 +// #define KB_FIRMWARE_VERSION_620 6 +// #define KB_FIRMWARE_VERSION_700 7 +// #define KB_FIRMWARE_VERSION_810 8 +// #define KB_FIRMWARE_VERSION_900 9 +// #define KB_FIRMWARE_VERSION_910 10 +// #define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 -#define HOS_PKG11_MAGIC 0x31314B50 +// #define HOS_PKG11_MAGIC 0x31314B50 #define COLOR_RED 0xFFE70000 #define COLOR_ORANGE 0xFFFF8C00 diff --git a/source/utils/util.c b/source/utils/util.c index cae1981..a6455fe 100644 --- a/source/utils/util.c +++ b/source/utils/util.c @@ -17,6 +17,7 @@ #include "util.h" #include "../gfx/di.h" +#include "../mem/heap.h" #include "../mem/minerva.h" #include "../power/max77620.h" #include "../rtc/max77620-rtc.h" @@ -24,13 +25,12 @@ #include "../soc/i2c.h" #include "../soc/pmc.h" #include "../soc/t210.h" +#include "../storage/nx_sd.h" #define USE_RTC_TIMER extern volatile nyx_storage_t *nyx_str; -extern void sd_unmount(); - u32 get_tmr_s() { return RTC(APBDEV_RTC_SECONDS); @@ -82,6 +82,43 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) base[ops[i].off] = ops[i].val; } +u32 crc32_calc(u32 crc, const u8 *buf, u32 len) +{ + const u8 *p, *q; + static u32 *table = NULL; + + // Calculate CRC table. + if (!table) + { + table = calloc(256, sizeof(u32)); + for (u32 i = 0; i < 256; i++) + { + u32 rem = i; + for (u32 j = 0; j < 8; j++) + { + if (rem & 1) + { + rem >>= 1; + rem ^= 0xedb88320; + } + else + rem >>= 1; + } + table[i] = rem; + } + } + + crc = ~crc; + q = buf + len; + for (p = buf; p < q; p++) + { + u8 oct = *p; + crc = (crc >> 8) ^ table[(crc & 0xff) ^ oct]; + } + + return ~crc; +} + void panic(u32 val) { // Set panic code. @@ -117,7 +154,7 @@ void reboot_rcm() nyx_str->mtc_cfg.init_done = 0; - PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm. + PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; while (true) @@ -128,6 +165,8 @@ void power_off() { sd_unmount(); display_end(); + + nyx_str->mtc_cfg.init_done = 0; // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); diff --git a/source/utils/util.h b/source/utils/util.h index 9ee1a74..d918194 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -21,8 +21,19 @@ #include "types.h" #include "../mem/minerva.h" -#define NYX_CFG_DUMP (1 << 7) -#define NYX_CFG_MINERVA (1 << 8) +typedef enum +{ + NYX_CFG_UMS = (1 << 6), + NYX_CFG_DUMP = (1 << 7), +} nyx_cfg_t; + +typedef enum +{ + ERR_LIBSYS_LP0 = (1 << 0), + ERR_SYSOLD_NYX = (1 << 1), + ERR_SYSOLD_MTC = (1 << 2), + ERR_EXCEPT_ENB = (1 << 31), +} hekate_errors_t; #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) @@ -35,7 +46,7 @@ typedef struct _cfg_op_t typedef struct _nyx_info_t { - u32 rsvd; + u32 disp_id; u32 errors; } nyx_info_t; @@ -61,5 +72,6 @@ void reboot_normal(); void reboot_rcm(); void power_off(); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); +u32 crc32_calc(u32 crc, const u8 *buf, u32 len); #endif From 4a69ea192232cb0e0967eea05c8a19bc5bf18a79 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 18 May 2020 15:52:19 -0600 Subject: [PATCH 068/166] Add FSS0 support --- source/hos/fss.c | 27 ---------------- source/hos/sept.c | 81 +++++++++++++++++++++++++++++++++------------- source/keys/keys.c | 10 +++++- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/source/hos/fss.c b/source/hos/fss.c index 8e255ea..a68deeb 100644 --- a/source/hos/fss.c +++ b/source/hos/fss.c @@ -79,31 +79,6 @@ typedef struct _fss_content_t char name[0x10]; } fss_content_t; -static void _update_r2p(const char *path) -{ - char *r2p_path = malloc(256); - u32 path_len = strlen(path); - strcpy(r2p_path, path); - - while(path_len) - { - if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C)) - { - r2p_path[path_len] = 0; - strcat(r2p_path, "reboot_payload.bin"); - u8 *r2p_payload = sd_file_read(r2p_path, NULL); - - is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false); - - free(r2p_payload); - break; - } - path_len--; - } - - free(r2p_path); -} - int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) { FIL fp; @@ -224,8 +199,6 @@ out: gfx_printf("Done!\n"); f_close(&fp); - _update_r2p(path); - return (!sept_ctxt ? 1 : sept_used); } diff --git a/source/hos/sept.c b/source/hos/sept.c index 4d4c6fa..84d0181 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -17,7 +17,9 @@ #include #include "sept.h" +#include "../config/ini.h" #include "../gfx/di.h" +#include "../hos/fss.h" #include "../hos/hos.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" @@ -28,6 +30,7 @@ #include "../storage/nx_sd.h" #include "../storage/sdmmc.h" #include "../utils/btn.h" +#include "../utils/list.h" #include "../utils/types.h" #include "../gfx/gfx.h" @@ -65,42 +68,76 @@ extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) { FIL fp; + bool fss0_sept_used = false; // Copy warmboot reboot code and TSEC fw. memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); *(vu32 *)SEPT_TCSZ_ADDR = tsec_size; - // Copy sept-primary. - if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) - goto error; + LIST_INIT(ini_sections); + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + { + bool found = false; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Only parse non config sections. + if (ini_sec->type == INI_CHOICE && strcmp(ini_sec->name, "config")) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("fss0", kv->key)) + { + fss0_sept_t sept_ctxt; + sept_ctxt.kb = kb; + sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR; + sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR; + fss0_sept_used = parse_fss(NULL, kv->val, &sept_ctxt); - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; + found = true; + break; + } + } + } + if (found) + break; + } } - f_close(&fp); - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) + + if (!fss0_sept_used) { - if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) + // Copy sept-primary. + if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) goto error; - } - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { + if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Copy sept-secondary. + if (kb < KB_FIRMWARE_VERSION_810) + { + if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) + if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. + goto error; + } + else + { + if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) + goto error; + } + + if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } f_close(&fp); - goto error; } - f_close(&fp); // Save auto boot config to sept payload, if any. boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); diff --git a/source/keys/keys.c b/source/keys/keys.c index 5097a10..c29ab2c 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -304,7 +304,7 @@ get_tsec: ; break; } memcpy(master_key[kb-1], master_key[kb], 0x10); - memcpy(master_key[kb], zeros, 0x10); + memset(master_key[kb], 0, 0x10); } if (_key_exists(temp_key)) { EPRINTF("Unable to derive master key."); @@ -527,6 +527,8 @@ pkg2_done: for (u32 j = 0; j < 3; j++) { _generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); + if (j == 2) + gfx_hexdump(i, key_area_key[j][i], 0x10); } } se_aes_key_set(8, master_key[i], 0x10); @@ -1088,8 +1090,14 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char temp_name[0x40] = {0}; + if (memcmp(name, "key_area_key_system", 19) == 0) { + gfx_hexdump(0, data, num_keys * 0x10); + } for (u32 i = 0; i < num_keys; i++) { sprintf(temp_name, "%s_%02x", name, i + start_key); + if (memcmp(name, "key_area_key_system", 19) == 0) { + gfx_printf("attempt save key %x\n", i); + } _save_key(temp_name, data + i * len, len, outbuf); } } From afd17a13ba81454335da9d747356eac1ccc9807a Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 18 May 2020 16:51:37 -0600 Subject: [PATCH 069/166] Add memcmp result checks to avoid gcc optimization --- source/keys/key_sources.inl | 2 +- source/keys/keys.c | 14 +++----------- source/keys/save.c | 2 +- source/main.c | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index dca7303..1388713 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -static const u8 zeros[0x10] = {0}; +static u8 zeros[0x10] = {0}; static const u8 keyblob_key_source[][0x10] = { {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 diff --git a/source/keys/keys.c b/source/keys/keys.c index c29ab2c..52bcdce 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -84,7 +84,7 @@ static inline u32 _read_le_u32(const void *buffer, u32 offset) { } // key functions -static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; +static int _key_exists(const void *data) { return memcmp(data, zeros, 0x10) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); @@ -334,7 +334,7 @@ get_tsec: ; emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); se_aes_key_set(3, keyblob_mac_key[i], 0x10); se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); - if (memcmp(keyblob_block, keyblob_mac, 0x10)) { + if (memcmp(keyblob_block, keyblob_mac, 0x10) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); gfx_hexdump(i, keyblob_block, 0x10); gfx_hexdump(i, keyblob_mac, 0x10); @@ -527,8 +527,6 @@ pkg2_done: for (u32 j = 0; j < 3; j++) { _generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); - if (j == 2) - gfx_hexdump(i, key_area_key[j][i], 0x10); } } se_aes_key_set(8, master_key[i], 0x10); @@ -936,7 +934,7 @@ get_titlekeys: u8 *db = M + 0x21; _mgf1_xor(salt, 0x20, db, 0xdf); _mgf1_xor(db, 0xdf, salt, 0x20); - if (memcmp(db, null_hash, 0x20)) + if (memcmp(db, null_hash, 0x20) != 0) continue; memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); _titlekey_count++; @@ -1090,14 +1088,8 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char temp_name[0x40] = {0}; - if (memcmp(name, "key_area_key_system", 19) == 0) { - gfx_hexdump(0, data, num_keys * 0x10); - } for (u32 i = 0; i < num_keys; i++) { sprintf(temp_name, "%s_%02x", name, i + start_key); - if (memcmp(name, "key_area_key_system", 19) == 0) { - gfx_printf("attempt save key %x\n", i); - } _save_key(temp_name, data + i * len, len, outbuf); } } diff --git a/source/keys/save.c b/source/keys/save.c index 8e11c9a..ea958d3 100644 --- a/source/keys/save.c +++ b/source/keys/save.c @@ -279,7 +279,7 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf hash[0x1F] |= 0x80; free(data_buffer); - if (memcmp(hash_buffer, hash, 0x20)) { + if (memcmp(hash_buffer, hash, 0x20) != 0) { ctx->block_validities[block_index] = VALIDITY_INVALID; } else { ctx->block_validities[block_index] = VALIDITY_VALID; diff --git a/source/main.c b/source/main.c index 855a4af..41fe132 100644 --- a/source/main.c +++ b/source/main.c @@ -237,7 +237,7 @@ void launch_tools() if (file_sec) { - if (memcmp("sd:/", file_sec, 4)) + if (memcmp("sd:/", file_sec, 4) != 0) { memcpy(dir + strlen(dir), "/", 2); memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1); From c7972f043da3c9871e768470b6ccb5d63837070e Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 18 May 2020 17:10:00 -0600 Subject: [PATCH 070/166] Bump version to v1.8.3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0dddc20..41094e8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 2 +LPVERSION_BUGFX := 3 ################################################################################ From d8586b4763cd2bf44abb8df3c5bbed41d97552c1 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 17 Jun 2020 10:30:58 -0600 Subject: [PATCH 071/166] fatfs: Merge some hekate changes --- source/libs/fatfs/ff.c | 130 +++++++++++++++++++++++------------------ source/libs/fatfs/ff.h | 2 +- 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index c48c036..7217103 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -38,10 +38,8 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ -#include "../../gfx/gfx.h" -#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); -//#define EFSPRINTF(...) +#define EFSPRINTF(text, ...) /*-------------------------------------------------------------------------- @@ -532,7 +530,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } -#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ +#define MAX_MALLOC 0x4000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN @@ -592,16 +590,6 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); ---------------------------------------------------------------------------*/ -/*-----------------------------------------------------------------------*/ -/* Print error header */ -/*-----------------------------------------------------------------------*/ - -void print_error() -{ - gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF); -} - - /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ @@ -3921,13 +3909,12 @@ FRESULT f_read_fast ( FATFS *fs; UINT csize_bytes; DWORD clst; - UINT count = 0; + DWORD wbytes; + UINT count; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; BYTE *wbuff = (BYTE*)buff; - // TODO support sector reading inside a cluster - res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); @@ -3939,6 +3926,17 @@ FRESULT f_read_fast ( if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ csize_bytes = fs->csize * SS(fs); + DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ + + /* If inside a cluster, read the sectors and align to cluster. */ + if (csect) { + wbytes = MIN(btr, (fs->csize - csect) * SS(fs)); + f_read(fp, wbuff, wbytes, (void *)0); + wbuff += wbytes; + btr -= wbytes; + if (!btr) + goto out; + } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ @@ -3946,15 +3944,22 @@ FRESULT f_read_fast ( if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } } + if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ + wbytes = MIN(btr, csize_bytes); sector_base = clst2sect(fs, fp->clust); - count += fs->csize; - btr -= csize_bytes; - fp->fptr += csize_bytes; + count = wbytes / SS(fs); + fp->fptr += wbytes; + btr -= wbytes; + + if (!btr) { /* Final cluster/sectors read. */ + if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + goto out; + } while (btr) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ @@ -3965,26 +3970,25 @@ FRESULT f_read_fast ( fp->clust = clst; work_sector = clst2sect(fs, fp->clust); - if ((work_sector - sector_base) == count) count += fs->csize; + wbytes = MIN(btr, csize_bytes); + if ((work_sector - sector_base) == count) count += wbytes / SS(fs); else { if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; - count = fs->csize; + count = wbytes / SS(fs); } - fp->fptr += MIN(btr, csize_bytes); - btr -= MIN(btr, csize_bytes); - - // TODO: what about if data is smaller than cluster? - // Must read-write back that cluster. + fp->fptr += wbytes; + btr -= wbytes; if (!btr) { /* Final cluster/sectors read. */ if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); } } +out: LEAVE_FF(fs, FR_OK); } #endif @@ -4147,12 +4151,11 @@ FRESULT f_write_fast ( FATFS *fs; UINT csize_bytes; DWORD clst; - UINT count = 0; + DWORD wbytes; + UINT count; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; - const BYTE *wbuff = (const BYTE*)buff; - - // TODO support sector writing inside a cluster + BYTE *wbuff = (BYTE*)buff; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { @@ -4167,6 +4170,19 @@ FRESULT f_write_fast ( } csize_bytes = fs->csize * SS(fs); + DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ + + /* If inside a cluster, write the sectors and align to cluster. */ + if (csect) { + wbytes = MIN(btw, (fs->csize - csect) * SS(fs)); + f_write(fp, wbuff, wbytes, (void *)0); + /* Ensure flushing of it. FatFS is not notified for next write if raw. */ + f_sync(fp); + wbuff += wbytes; + btw -= wbytes; + if (!btw) + goto out; + } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ @@ -4176,44 +4192,51 @@ FRESULT f_write_fast ( } if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } - else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ + wbytes = MIN(btw, csize_bytes); sector_base = clst2sect(fs, fp->clust); - count += fs->csize; - btw -= csize_bytes; - fp->fptr += csize_bytes; + count = wbytes / SS(fs); + fp->fptr += wbytes; + btw -= wbytes; + + if (!btw) { /* Final cluster/sectors write. */ + if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + goto out; + } while (btw) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } - else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; work_sector = clst2sect(fs, fp->clust); - if ((work_sector - sector_base) == count) count += fs->csize; + wbytes = MIN(btw, csize_bytes); + if ((work_sector - sector_base) == count) count += wbytes / SS(fs); else { if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; - count = fs->csize; + count = wbytes / SS(fs); } - fp->fptr += MIN(btw, csize_bytes); - btw -= MIN(btw, csize_bytes); + fp->fptr += wbytes; + btw -= wbytes; - // what about if data is smaller than cluster? - // Probably must read-write back that cluster. if (!btw) { /* Final cluster/sectors write. */ if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } } +out: fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); @@ -4689,19 +4712,17 @@ FRESULT f_lseek ( DWORD *f_expand_cltbl ( FIL* fp, /* Pointer to the file object */ UINT tblsz, /* Size of table */ + DWORD *tbl, /* Table pointer */ FSIZE_t ofs /* File pointer from top of file */ ) { if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ - if (!fp->cltbl) { /* Allocate memory for cluster link table */ - fp->cltbl = (DWORD *)ff_memalloc(tblsz); - fp->cltbl[0] = tblsz; - } + fp->cltbl = (DWORD *)tbl; + fp->cltbl[0] = tblsz; if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ - ff_memfree(fp->cltbl); - fp->cltbl = NULL; + fp->cltbl = (void *)0; EFSPRINTF("CLTBLSZ"); - return NULL; + return (void *)0; } f_lseek(fp, 0); @@ -5842,7 +5863,7 @@ FRESULT f_mkfs ( UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ @@ -5906,7 +5927,7 @@ FRESULT f_mkfs ( } else { /* Create a single-partition in this function */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */ + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } @@ -6130,9 +6151,6 @@ FRESULT f_mkfs ( if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ - if (n % n_fats) { /* Adjust fractional error if needed */ - n--; sz_rsv++; b_fat++; - } sz_fat += n / n_fats; } @@ -6196,13 +6214,13 @@ FRESULT f_mkfs ( st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ diff --git a/source/libs/fatfs/ff.h b/source/libs/fatfs/ff.h index 6c47c73..6ace114 100644 --- a/source/libs/fatfs/ff.h +++ b/source/libs/fatfs/ff.h @@ -289,7 +289,7 @@ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ #ifdef FF_FASTFS -DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */ +DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, DWORD *tbl, FSIZE_t ofs); /* Expand file and populate cluster table */ #endif FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ From 7649eb13628089dee87c4138e2122bf1df46b6cb Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 17 Jun 2020 10:31:29 -0600 Subject: [PATCH 072/166] Improve code readability --- source/hos/pkg1.c | 61 ++++++++++++++++++++++++++++++++++---- source/hos/pkg1.h | 14 +++++++++ source/keys/keys.c | 46 ++++++++++++++-------------- source/keys/save.h | 2 +- source/libs/fatfs/ffconf.h | 2 +- source/sec/se.c | 4 +-- 6 files changed, 97 insertions(+), 32 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index b1768f8..e80f964 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -22,10 +22,61 @@ #include "pkg1.h" #include "../sec/se.h" -#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_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1} -#define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1} +#define HASH_ORDER_100_100 { \ + FS_KEY_AREA_KEY_APPLI_SOURCE, \ + FS_KEY_AREA_KEY_OCEAN_SOURCE, \ + FS_KEY_AREA_KEY_SYSTE_SOURCE, \ + FS_HEADER_KEK_SOURCE, \ + FS_SAVE_MAC_KEK_SOURCE, \ + FS_SAVE_MAC_KEY_SOURCE, \ + FS_HEADER_KEY_SOURCE \ + } + +#define HASH_ORDER_200_510 { \ + FS_KEY_AREA_KEY_APPLI_SOURCE, \ + FS_KEY_AREA_KEY_OCEAN_SOURCE, \ + FS_KEY_AREA_KEY_SYSTE_SOURCE, \ + FS_HEADER_KEK_SOURCE, \ + FS_SAVE_MAC_KEK_SOURCE, \ + FS_SAVE_MAC_SD_KEK_SOURCE, \ + FS_SD_KEK_SOURCE, \ + FS_SD_SAVE_KEY_SOURCE, \ + FS_SD_NCA_KEY_SOURCE, \ + FS_SAVE_MAC_KEY_SOURCE, \ + FS_SAVE_MAC_SD_KEY_SOURCE, \ + FS_HEADER_KEY_SOURCE \ + } + +#define HASH_ORDER_600_620 { \ + FS_SAVE_MAC_KEY_SOURCE, \ + FS_SAVE_MAC_KEK_SOURCE, \ + FS_SD_KEK_SOURCE, \ + FS_SAVE_MAC_SD_KEK_SOURCE, \ + FS_SAVE_MAC_SD_KEY_SOURCE, \ + FS_KEY_AREA_KEY_APPLI_SOURCE, \ + FS_KEY_AREA_KEY_OCEAN_SOURCE, \ + FS_KEY_AREA_KEY_SYSTE_SOURCE, \ + FS_HEADER_KEK_SOURCE, \ + FS_SD_SAVE_KEY_SOURCE, \ + FS_SD_NCA_KEY_SOURCE, \ + FS_HEADER_KEY_SOURCE \ + } + +#define HASH_ORDER_700_10x { \ + FS_SAVE_MAC_KEY_SOURCE, \ + FS_SAVE_MAC_KEK_SOURCE, \ + FS_SD_KEK_SOURCE, \ + FS_SAVE_MAC_SD_KEK_SOURCE, \ + FS_SAVE_MAC_SD_KEY_SOURCE, \ + FS_KEY_AREA_KEY_APPLI_SOURCE, \ + FS_KEY_AREA_KEY_OCEAN_SOURCE, \ + FS_KEY_AREA_KEY_SYSTE_SOURCE, \ + FS_HEADER_KEK_SOURCE, \ + FS_SD_SAVE_KEY_SOURCE, \ + FS_SD_NCA_KEY_SOURCE, \ + FS_SD_CUSTOM_KEY_SOURCE, \ + FS_HEADER_KEY_SOURCE \ + } static const pkg1_id_t _pkg1_ids[] = { { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0 @@ -42,7 +93,7 @@ static const pkg1_id_t _pkg1_ids[] = { { "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_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 { "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 + { "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0+ { NULL } //End. }; diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index 1d1e4ad..a7d6a8d 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -19,6 +19,20 @@ #include "../utils/types.h" +#define FS_HEADER_KEK_SOURCE 0 +#define FS_HEADER_KEY_SOURCE 1 +#define FS_KEY_AREA_KEY_APPLI_SOURCE 2 +#define FS_KEY_AREA_KEY_OCEAN_SOURCE 3 +#define FS_KEY_AREA_KEY_SYSTE_SOURCE 4 +#define FS_SAVE_MAC_KEK_SOURCE 5 +#define FS_SAVE_MAC_KEY_SOURCE 6 +#define FS_SAVE_MAC_SD_KEK_SOURCE 7 +#define FS_SAVE_MAC_SD_KEY_SOURCE 8 +#define FS_SD_CUSTOM_KEY_SOURCE 9 +#define FS_SD_KEK_SOURCE 10 +#define FS_SD_NCA_KEY_SOURCE 11 +#define FS_SD_SAVE_KEY_SOURCE 12 + typedef struct _key_info_t { u32 start_offset; diff --git a/source/keys/keys.c b/source/keys/keys.c index 52bcdce..d49be51 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -472,7 +472,7 @@ get_tsec: ; if (!pkg1_not_100) { // 1.0.0 doesn't have SD keys at all and the first key isn't aligned with the rest - memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); + memcpy(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); hash_index = 1; } @@ -506,15 +506,15 @@ pkg2_done: TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); - if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { - _generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[1] + 0x00); - se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[1] + 0x10); + if (_key_exists(fs_keys[FS_HEADER_KEK_SOURCE]) && _key_exists(fs_keys[FS_HEADER_KEY_SOURCE]) && _key_exists(master_key[0])) { + _generate_kek(8, fs_keys[FS_HEADER_KEK_SOURCE], master_key[0], aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[FS_HEADER_KEY_SOURCE] + 0x00); + se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[FS_HEADER_KEY_SOURCE] + 0x10); } - if (_key_exists(fs_keys[5]) && _key_exists(fs_keys[6]) && _key_exists(device_key)) { - _generate_kek(8, fs_keys[5], device_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[6]); + if (_key_exists(fs_keys[FS_SAVE_MAC_KEK_SOURCE]) && _key_exists(fs_keys[FS_SAVE_MAC_KEY_SOURCE]) && _key_exists(device_key)) { + _generate_kek(8, fs_keys[FS_SAVE_MAC_KEK_SOURCE], device_key, aes_kek_generation_source, NULL); + se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[FS_SAVE_MAC_KEY_SOURCE]); } if (_key_exists(master_key[MAX_KEY])) { @@ -523,9 +523,9 @@ pkg2_done: for (u32 i = 0; i < MAX_KEY; i++) { if (!_key_exists(master_key[i])) continue; - if (_key_exists(fs_keys[2]) && _key_exists(fs_keys[3]) && _key_exists(fs_keys[4])) { + if (_key_exists(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE])) { for (u32 j = 0; j < 3; j++) { - _generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL); + _generate_kek(8, fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE + j], master_key[i], aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); } } @@ -981,15 +981,15 @@ key_output: ; SAVE_KEY("eticket_rsa_kek_personalized", eticket_rsa_kek_personalized, 0x10); SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10); - SAVE_KEY("header_kek_source", fs_keys[0], 0x10); + SAVE_KEY("header_kek_source", fs_keys[FS_HEADER_KEK_SOURCE], 0x10); SAVE_KEY("header_key", header_key, 0x20); - SAVE_KEY("header_key_source", fs_keys[1], 0x20); + SAVE_KEY("header_key_source", fs_keys[FS_HEADER_KEY_SOURCE], 0x20); SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10); + SAVE_KEY("key_area_key_application_source", fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], 0x10); SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10); + SAVE_KEY("key_area_key_ocean_source", fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE], 0x10); SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10); + SAVE_KEY("key_area_key_system_source", fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE], 0x10); SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); @@ -1010,15 +1010,15 @@ key_output: ; for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; SAVE_KEY("rsa_private_kek_generation_source", temp_key, 0x10); - SAVE_KEY("save_mac_kek_source", fs_keys[5], 0x10); + SAVE_KEY("save_mac_kek_source", fs_keys[FS_SAVE_MAC_KEK_SOURCE], 0x10); SAVE_KEY("save_mac_key", save_mac_key, 0x10); - SAVE_KEY("save_mac_key_source", fs_keys[6], 0x10); - SAVE_KEY("save_mac_sd_card_kek_source", fs_keys[7], 0x10); - SAVE_KEY("save_mac_sd_card_key_source", fs_keys[8], 0x10); - SAVE_KEY("sd_card_custom_storage_key_source", fs_keys[9], 0x20); - SAVE_KEY("sd_card_kek_source", fs_keys[10], 0x10); - SAVE_KEY("sd_card_nca_key_source", fs_keys[11], 0x20); - SAVE_KEY("sd_card_save_key_source", fs_keys[12], 0x20); + SAVE_KEY("save_mac_key_source", fs_keys[FS_SAVE_MAC_KEY_SOURCE], 0x10); + SAVE_KEY("save_mac_sd_card_kek_source", fs_keys[FS_SAVE_MAC_SD_KEK_SOURCE], 0x10); + SAVE_KEY("save_mac_sd_card_key_source", fs_keys[FS_SAVE_MAC_SD_KEY_SOURCE], 0x10); + SAVE_KEY("sd_card_custom_storage_key_source", fs_keys[FS_SD_CUSTOM_KEY_SOURCE], 0x20); + SAVE_KEY("sd_card_kek_source", fs_keys[FS_SD_KEK_SOURCE], 0x10); + SAVE_KEY("sd_card_nca_key_source", fs_keys[FS_SD_NCA_KEY_SOURCE], 0x20); + SAVE_KEY("sd_card_save_key_source", fs_keys[FS_SD_SAVE_KEY_SOURCE], 0x20); SAVE_KEY("sd_seed", sd_seed, 0x10); SAVE_KEY("secure_boot_key", sbk, 0x10); SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); diff --git a/source/keys/save.h b/source/keys/save.h index c42b7bf..a89a675 100644 --- a/source/keys/save.h +++ b/source/keys/save.h @@ -193,7 +193,7 @@ typedef struct { } remap_storage_ctx_t; typedef struct { - uint64_t title_id; + uint64_t program_id; uint8_t user_id[0x10]; uint64_t save_id; uint8_t save_data_type; diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index ebd7f22..af35a21 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -41,7 +41,7 @@ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define FF_FASTFS 0 +#define FF_FASTFS 0 #if FF_FASTFS #define FF_USE_FASTSEEK 1 diff --git a/source/sec/se.c b/source/sec/se.c index 484f3c8..768d772 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -418,8 +418,8 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo u8 *tweak = (u8 *)malloc(0x10); u8 *temptweak = (u8 *)malloc(0x10); u32 *pdst = (u32 *)dst; - u32 *psrc = (u32 *)src; - u32 *ptweak = (u32 *)tweak; + u32 *psrc = (u32 *)src; + u32 *ptweak = (u32 *)tweak; //Generate tweak. for (int i = 0xF; i >= 0; i--) From 47f749c6feedf2fc90a9d7a4f67f9ecd87436922 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 17 Jun 2020 10:37:48 -0600 Subject: [PATCH 073/166] Support sept from Atmosphere 0.13.0 --- source/keys/keys.c | 2 +- source/sec/se.c | 5 +++++ source/sec/se.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index d49be51..781596f 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -234,7 +234,7 @@ void dump_keys() { if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) goto out_wait; } else { - se_aes_key_read(12, master_key[KB_FIRMWARE_VERSION_MAX], 0x10); + se_aes_key_read(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, master_key[KB_FIRMWARE_VERSION_MAX], 0x10); } } diff --git a/source/sec/se.c b/source/sec/se.c index 768d772..0fad5a8 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -230,6 +230,11 @@ void se_key_acc_ctrl(u32 ks, u32 flags) SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); } +u32 se_key_acc_ctrl_get(u32 ks) +{ + return SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks); +} + void se_aes_key_set(u32 ks, const void *key, u32 size) { u32 *data = (u32 *)key; diff --git a/source/sec/se.h b/source/sec/se.h index 211c279..5172403 100644 --- a/source/sec/se.h +++ b/source/sec/se.h @@ -24,6 +24,7 @@ void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 void se_rsa_key_clear(u32 ks); int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); void se_key_acc_ctrl(u32 ks, u32 flags); +u32 se_key_acc_ctrl_get(u32 ks); void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_iv_set(u32 ks, const void *iv, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size); From 1881583eeae0fbe54156b8ba38a03629aa325e34 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 17 Jun 2020 10:39:02 -0600 Subject: [PATCH 074/166] Bump version to v1.8.4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 41094e8..404fec4 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 3 +LPVERSION_BUGFX := 4 ################################################################################ From 4425e8108528ab18a0837e8fc70571c112c2c0b2 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 25 Jun 2020 15:11:40 -0600 Subject: [PATCH 075/166] Sector -> cluster cache, optimize _gf256_mul_x_le --- source/keys/keys.c | 18 ++-- source/libs/fatfs/diskio.c | 201 +++++++++++++++++++++---------------- source/sec/se.c | 18 ++-- 3 files changed, 132 insertions(+), 105 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 781596f..e60c9a7 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -51,9 +51,9 @@ extern hekate_config h_cfg; -extern bool clear_sector_cache; -extern bool lock_sector_cache; -extern u32 secindex; +extern bool clear_cluster_cache; +extern bool lock_cluster_cache; +extern u32 cluster_cache_index; u32 _key_count = 0, _titlekey_count = 0; u32 color_idx = 0; @@ -593,6 +593,7 @@ pkg2_done: } path[25] = '/'; + lock_cluster_cache = true; while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); memcpy(path + 26, fno.fname, 36); @@ -614,7 +615,6 @@ pkg2_done: } hash_index = 0; // decrypt only what is needed to locate needed keys - lock_sector_cache = true; temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); for (u32 i = 0; i <= 0xb0; ) { se_calc_sha256(temp_hash, temp_file + i, 0x10); @@ -631,9 +631,7 @@ pkg2_done: free(temp_file); temp_file = NULL; titles_found++; - lock_sector_cache = false; } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { - lock_sector_cache = true; temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); @@ -653,12 +651,12 @@ pkg2_done: free(temp_file); temp_file = NULL; titles_found++; - lock_sector_cache = false; } f_close(&fp); } f_closedir(&dir); free(dec_header); + lock_cluster_cache = false; // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { @@ -799,7 +797,7 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - clear_sector_cache = true; + clear_cluster_cache = true; save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e1 save."); @@ -876,7 +874,7 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - clear_sector_cache = true; + clear_cluster_cache = true; save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e2 save."); @@ -958,7 +956,7 @@ dismount:; free(save_ctx); } f_mount(NULL, "emmc:", 1); - clear_sector_cache = true; + clear_cluster_cache = true; nx_emmc_gpt_free(&gpt); key_output: ; diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 2cfacd7..6df8e3e 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -37,19 +37,26 @@ extern sdmmc_storage_t sd_storage; extern sdmmc_storage_t storage; extern emmc_part_t *system_part; -typedef struct { - u32 sector; - u32 visit_count; - u8 align[8]; - u8 tweak[0x10]; - u8 cached_sector[0x200]; -} sector_cache_t; +#define MAX_CLUSTER_CACHE_ENTRIES 128 +#define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF +#define XTS_CLUSTER_SIZE 0x4000 +#define SECTORS_PER_CLUSTER 0x20 -#define MAX_SEC_CACHE_ENTRIES 256 -static sector_cache_t *sector_cache = (sector_cache_t *)(MIXD_BUF_ALIGNED + 0x100000); //NULL; -u32 secindex = 0; -bool clear_sector_cache = false; -bool lock_sector_cache = false; +typedef struct { + u32 cluster_num; // index of the cluster in the partition + u32 visit_count; // used for debugging/access analysis + u8 dirty; // has been modified without writeback flag + u8 align[7]; + u8 cluster[XTS_CLUSTER_SIZE]; // the cached cluster itself +} cluster_cache_t; + +static cluster_cache_t *cluster_cache = (cluster_cache_t *)RAM_DISK_ADDR; +u32 cluster_cache_index = 0; +u32 *cluster_lookup = (u32 *)(RAM_DISK_ADDR + MAX_CLUSTER_CACHE_ENTRIES * sizeof(cluster_cache_t)); +u8 *emmc_buffer = (u8 *)(MIXD_BUF_ALIGNED + 0x100000); + +bool clear_cluster_cache = false; +bool lock_cluster_cache = false; DSTATUS disk_status ( BYTE pdrv /* Physical drive number to identify the drive */ @@ -65,21 +72,23 @@ DSTATUS disk_initialize ( return 0; } -static inline void _gf256_mul_x_le(void *block) { - u8 *pdata = (u8 *)block; +static inline void _gf256_mul_x_le(void *block) +{ + u32 *pdata = (u32 *)block; u32 carry = 0; - for (u32 i = 0; i < 0x10; i++) { - u8 b = pdata[i]; + for (u32 i = 0; i < 4; i++) { + u32 b = pdata[i]; pdata[i] = (b << 1) | carry; - carry = b >> 7; + carry = b >> 31; } if (carry) pdata[0x0] ^= 0x87; } -static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) { +static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) +{ int res = 0; u8 *temptweak = (u8 *)malloc(0x10); u32 *pdst = (u32 *)dst; @@ -95,26 +104,33 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe goto out; } - for (u32 i = 0; i < tweak_exp * 0x20; i++) + // tweak_exp allows us to use a saved tweak to reduce _gf256_mul_x_le calls + for (u32 i = 0; i < tweak_exp * SECTORS_PER_CLUSTER; i++) _gf256_mul_x_le(tweak); memcpy(temptweak, tweak, 0x10); - //We are assuming a 0x10-aligned sector size in this implementation. - for (u32 i = 0; i < secsize / 0x10; i++) { + + // The reference implementation in IEEE P1619 encrypts once per AES block + // In this environment, doing so produces a lot of overhead + // Instead, we perform one single AES-ECB operation between the sector xors + + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < secsize / 0x10; i++) + { for (u32 j = 0; j < 4; j++) pdst[j] = psrc[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); psrc += 4; pdst += 4; } - se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); pdst = (u32 *)dst; memcpy(tweak, temptweak, 0x10); - for (u32 i = 0; i < secsize / 0x10; i++) { + for (u32 i = 0; i < secsize / 0x10; i++) + { for (u32 j = 0; j < 4; j++) pdst[j] = pdst[j] ^ ptweak[j]; _gf256_mul_x_le(tweak); @@ -138,74 +154,87 @@ DRESULT disk_read ( switch (pdrv) { case 0: - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - if (sdmmc_storage_read(&sd_storage, sector, count, buf)) - { - memcpy(buff, buf, 512 * count); - return RES_OK; - } - return RES_ERROR; + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; case 1:; __attribute__ ((aligned (16))) static u8 tweak[0x10]; __attribute__ ((aligned (16))) static u64 prev_cluster = -1; __attribute__ ((aligned (16))) static u32 prev_sector = 0; - bool needs_cache_sector = false; - if (secindex == 0 || clear_sector_cache) { - clear_sector_cache = false; - lock_sector_cache = false; - secindex = 0; + if (cluster_cache_index == 0 || clear_cluster_cache) + { + // memset gets optimized out... + // for (u32 i = 0; i < (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER; i++) + // cluster_lookup[i] = CLUSTER_LOOKUP_EMPTY_ENTRY; + memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * 4); + cluster_cache_index = 0; + clear_cluster_cache = false; + lock_cluster_cache = false; } - u32 s = 0; - // only attempt to cache single-sector reads as these are most likely to be repeated (eg. rereading FAT) - if (!lock_sector_cache && count == 1) { - for ( ; s < secindex; s++) { - if (sector_cache[s].sector == sector) { - sector_cache[s].visit_count++; - memcpy(buff, sector_cache[s].cached_sector, 0x200); - memcpy(tweak, sector_cache[s].tweak, 0x10); - prev_sector = sector; - prev_cluster = sector / 0x20; - return RES_OK; - } - } - // add to cache - if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) { - sector_cache[s].sector = sector; - sector_cache[s].visit_count++; - needs_cache_sector = true; - secindex++; - } - } + u32 cluster = sector / SECTORS_PER_CLUSTER; + u32 aligned_sector = cluster * SECTORS_PER_CLUSTER; + u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; + u32 cluster_lookup_index = cluster_lookup[cluster]; - if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) { - u32 tweak_exp = 0; - bool regen_tweak = true; - if (prev_cluster != sector / 0x20) { // sector in different cluster than last read - prev_cluster = sector / 0x20; - tweak_exp = sector % 0x20; - } else if (sector > prev_sector) { // sector in same cluster and past last sector - tweak_exp = sector - prev_sector - 1; - regen_tweak = false; - } else { // sector in same cluster and before or same as last sector - tweak_exp = sector % 0x20; - } - - // fatfs will never pull more than a cluster - _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200); - if (needs_cache_sector) { - memcpy(sector_cache[s].cached_sector, buff, 0x200); - memcpy(sector_cache[s].tweak, tweak, 0x10); - } + if (cluster_lookup_index != CLUSTER_LOOKUP_EMPTY_ENTRY) + { + memcpy(buff, cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); + cluster_cache[cluster_lookup_index].visit_count++; prev_sector = sector + count - 1; + prev_cluster = cluster; return RES_OK; } - return RES_ERROR; + + // Only cache single-sector reads as these are most likely to be repeated (eg. boot block, FAT directory tables) + if (count == 1 && + !lock_cluster_cache && + cluster_cache_index < MAX_CLUSTER_CACHE_ENTRIES && + cluster_lookup_index == CLUSTER_LOOKUP_EMPTY_ENTRY) + { + cluster_cache[cluster_cache_index].cluster_num = cluster; + cluster_cache[cluster_cache_index].visit_count = 1; + cluster_cache[cluster_cache_index].dirty = 0; + cluster_lookup[cluster] = cluster_cache_index; + + // Read and decrypt the whole cluster the sector resides in + if (!nx_emmc_part_read(&storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) + return RES_ERROR; + _emmc_xts(9, 8, 0, tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE); + memcpy(cluster_cache[cluster_cache_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); + memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE); + prev_cluster = -1; + prev_sector = 0; + cluster_cache_index++; + return RES_OK; + } + + if (!nx_emmc_part_read(&storage, system_part, sector, count, buff)) + return RES_ERROR; + u32 tweak_exp = 0; + bool regen_tweak = true; + if (prev_cluster != cluster) + { // Sector is in different cluster than last read + prev_cluster = cluster; + tweak_exp = sector_index_in_cluster; + } + else if (sector > prev_sector) + { // Sector is in same cluster and past last sector + // Calculates the new tweak using the saved one, reducing expensive _gf256_mul_x_le calls + tweak_exp = sector - prev_sector - 1; + regen_tweak = false; + } + else + { // Sector is in same cluster and before or same as last sector + tweak_exp = sector_index_in_cluster; + } + + // FatFs will never pull more than one 4K cluster, which is the same as the crypto 'sector' size + _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * NX_EMMC_BLOCKSIZE); + prev_sector = sector + count - 1; + return RES_OK; } + return RES_ERROR; } @@ -216,15 +245,15 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - if (pdrv == 1) - return RES_WRPRT; - - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + switch (pdrv) + { + case 0: return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere. - memcpy(buf, buff, 512 * count); - if (sdmmc_storage_write(&sd_storage, sector, count, buf)) - return RES_OK; + + case 1: + return RES_WRPRT; + } + return RES_ERROR; } diff --git a/source/sec/se.c b/source/sec/se.c index 0fad5a8..c6dbd8e 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -55,18 +55,18 @@ static void _gf256_mul_x(void *block) static void _gf256_mul_x_le(void *block) { - u8 *pdata = (u8 *)block; - u32 carry = 0; + u32 *pdata = (u32 *)block; + u32 carry = 0; - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < 4; i++) { - u8 b = pdata[i]; - pdata[i] = (b << 1) | carry; - carry = b >> 7; - } + u32 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 31; + } - if (carry) - pdata[0x0] ^= 0x87; + if (carry) + pdata[0x0] ^= 0x87; } static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) From 4ffd4ce7f0117c26277d411ce11b8ac1ad8a2d84 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 26 Jun 2020 14:17:06 -0600 Subject: [PATCH 076/166] Transition to hekate bdk layout --- Makefile | 25 +- bdk/exception_handlers.S | 233 ++ bdk/fatfs_cfg.h | 24 + {source => bdk}/gfx/di.c | 127 +- {source => bdk}/gfx/di.h | 15 +- {source => bdk}/gfx/di.inl | 110 +- bdk/gfx_utils.h | 24 + {source/libs => bdk/ianos}/elfload/elf.h | 0 {source/libs => bdk/ianos}/elfload/elfarch.h | 0 {source/libs => bdk/ianos}/elfload/elfload.c | 0 {source/libs => bdk/ianos}/elfload/elfload.h | 4 +- .../ianos}/elfload/elfreloc_aarch64.c | 0 .../libs => bdk/ianos}/elfload/elfreloc_arm.c | 0 {source => bdk}/ianos/ianos.c | 35 +- {source => bdk}/ianos/ianos.h | 4 +- bdk/input/als.c | 118 + bdk/input/als.h | 65 + bdk/input/joycon.c | 872 ++++++++ bdk/input/joycon.h | 98 + bdk/input/touch.c | 422 ++++ bdk/input/touch.h | 157 ++ {source => bdk}/libs/compr/blz.c | 0 {source => bdk}/libs/compr/blz.h | 2 +- {source => bdk}/libs/compr/lz.c | 0 {source => bdk}/libs/compr/lz.h | 0 {source => bdk}/libs/fatfs/diskio.h | 9 +- {source => bdk}/libs/fatfs/ff.c | 0 {source => bdk}/libs/fatfs/ff.h | 6 +- {source => bdk}/libs/fatfs/ffunicode.c | 0 bdk/libs/lv_conf.h | 369 +++ bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md | 46 + bdk/libs/lvgl/docs/CONTRIBUTING.md | 103 + bdk/libs/lvgl/docs/astyle_c | 1 + bdk/libs/lvgl/docs/astyle_h | 1 + bdk/libs/lvgl/licence.txt | 8 + bdk/libs/lvgl/lv_core/lv_core.mk | 12 + bdk/libs/lvgl/lv_core/lv_group.c | 554 +++++ bdk/libs/lvgl/lv_core/lv_group.h | 247 ++ bdk/libs/lvgl/lv_core/lv_indev.c | 971 ++++++++ bdk/libs/lvgl/lv_core/lv_indev.h | 157 ++ bdk/libs/lvgl/lv_core/lv_lang.c | 117 + bdk/libs/lvgl/lv_core/lv_lang.h | 74 + bdk/libs/lvgl/lv_core/lv_obj.c | 1986 +++++++++++++++++ bdk/libs/lvgl/lv_core/lv_obj.h | 840 +++++++ bdk/libs/lvgl/lv_core/lv_refr.c | 614 +++++ bdk/libs/lvgl/lv_core/lv_refr.h | 94 + bdk/libs/lvgl/lv_core/lv_style.c | 357 +++ bdk/libs/lvgl/lv_core/lv_style.h | 198 ++ bdk/libs/lvgl/lv_core/lv_vdb.c | 207 ++ bdk/libs/lvgl/lv_core/lv_vdb.h | 119 + bdk/libs/lvgl/lv_draw/lv_draw.c | 163 ++ bdk/libs/lvgl/lv_draw/lv_draw.h | 115 + bdk/libs/lvgl/lv_draw/lv_draw.mk | 14 + bdk/libs/lvgl/lv_draw/lv_draw_arc.c | 264 +++ bdk/libs/lvgl/lv_draw/lv_draw_arc.h | 53 + bdk/libs/lvgl/lv_draw/lv_draw_img.c | 759 +++++++ bdk/libs/lvgl/lv_draw/lv_draw_img.h | 167 ++ bdk/libs/lvgl/lv_draw/lv_draw_label.c | 264 +++ bdk/libs/lvgl/lv_draw/lv_draw_label.h | 53 + bdk/libs/lvgl/lv_draw/lv_draw_line.c | 607 +++++ bdk/libs/lvgl/lv_draw/lv_draw_line.h | 49 + bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c | 269 +++ bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h | 96 + bdk/libs/lvgl/lv_draw/lv_draw_rect.c | 1435 ++++++++++++ bdk/libs/lvgl/lv_draw/lv_draw_rect.h | 48 + bdk/libs/lvgl/lv_draw/lv_draw_triangle.c | 168 ++ bdk/libs/lvgl/lv_draw/lv_draw_triangle.h | 51 + bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c | 691 ++++++ bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h | 89 + bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c | 58 + bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c | 159 ++ bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c | 159 ++ bdk/libs/lvgl/lv_fonts/interui_20.c | 248 ++ bdk/libs/lvgl/lv_fonts/interui_30.c | 248 ++ bdk/libs/lvgl/lv_fonts/lv_font_builtin.c | 100 + bdk/libs/lvgl/lv_fonts/lv_font_builtin.h | 95 + bdk/libs/lvgl/lv_fonts/lv_fonts.mk | 14 + bdk/libs/lvgl/lv_fonts/ubuntu_mono.c | 248 ++ bdk/libs/lvgl/lv_hal/lv_hal.h | 40 + bdk/libs/lvgl/lv_hal/lv_hal.mk | 8 + bdk/libs/lvgl/lv_hal/lv_hal_disp.c | 242 ++ bdk/libs/lvgl/lv_hal/lv_hal_disp.h | 173 ++ bdk/libs/lvgl/lv_hal/lv_hal_indev.c | 135 ++ bdk/libs/lvgl/lv_hal/lv_hal_indev.h | 166 ++ bdk/libs/lvgl/lv_hal/lv_hal_tick.c | 100 + bdk/libs/lvgl/lv_hal/lv_hal_tick.h | 65 + bdk/libs/lvgl/lv_misc/lv_anim.c | 445 ++++ bdk/libs/lvgl/lv_misc/lv_anim.h | 176 ++ bdk/libs/lvgl/lv_misc/lv_area.c | 200 ++ bdk/libs/lvgl/lv_misc/lv_area.h | 168 ++ bdk/libs/lvgl/lv_misc/lv_circ.c | 79 + bdk/libs/lvgl/lv_misc/lv_circ.h | 80 + bdk/libs/lvgl/lv_misc/lv_color.c | 167 ++ bdk/libs/lvgl/lv_misc/lv_color.h | 455 ++++ bdk/libs/lvgl/lv_misc/lv_font.c | 269 +++ bdk/libs/lvgl/lv_misc/lv_font.h | 191 ++ bdk/libs/lvgl/lv_misc/lv_fs.c | 627 ++++++ bdk/libs/lvgl/lv_misc/lv_fs.h | 276 +++ bdk/libs/lvgl/lv_misc/lv_gc.c | 40 + bdk/libs/lvgl/lv_misc/lv_gc.h | 75 + bdk/libs/lvgl/lv_misc/lv_ll.c | 376 ++++ bdk/libs/lvgl/lv_misc/lv_ll.h | 145 ++ bdk/libs/lvgl/lv_misc/lv_log.c | 82 + bdk/libs/lvgl/lv_misc/lv_log.h | 86 + bdk/libs/lvgl/lv_misc/lv_math.c | 165 ++ bdk/libs/lvgl/lv_misc/lv_math.h | 73 + bdk/libs/lvgl/lv_misc/lv_mem.c | 470 ++++ bdk/libs/lvgl/lv_misc/lv_mem.h | 127 ++ bdk/libs/lvgl/lv_misc/lv_misc.mk | 19 + bdk/libs/lvgl/lv_misc/lv_symbol_def.h | 223 ++ bdk/libs/lvgl/lv_misc/lv_task.c | 332 +++ bdk/libs/lvgl/lv_misc/lv_task.h | 149 ++ bdk/libs/lvgl/lv_misc/lv_templ.c | 36 + bdk/libs/lvgl/lv_misc/lv_templ.h | 38 + bdk/libs/lvgl/lv_misc/lv_txt.c | 793 +++++++ bdk/libs/lvgl/lv_misc/lv_txt.h | 197 ++ bdk/libs/lvgl/lv_misc/lv_ufs.c | 516 +++++ bdk/libs/lvgl/lv_misc/lv_ufs.h | 213 ++ bdk/libs/lvgl/lv_objx/lv_arc.c | 310 +++ bdk/libs/lvgl/lv_objx/lv_arc.h | 127 ++ bdk/libs/lvgl/lv_objx/lv_bar.c | 429 ++++ bdk/libs/lvgl/lv_objx/lv_bar.h | 160 ++ bdk/libs/lvgl/lv_objx/lv_btn.c | 763 +++++++ bdk/libs/lvgl/lv_objx/lv_btn.h | 280 +++ bdk/libs/lvgl/lv_objx/lv_btnm.c | 881 ++++++++ bdk/libs/lvgl/lv_objx/lv_btnm.h | 197 ++ bdk/libs/lvgl/lv_objx/lv_calendar.c | 1038 +++++++++ bdk/libs/lvgl/lv_objx/lv_calendar.h | 246 ++ bdk/libs/lvgl/lv_objx/lv_canvas.c | 593 +++++ bdk/libs/lvgl/lv_objx/lv_canvas.h | 229 ++ bdk/libs/lvgl/lv_objx/lv_cb.c | 347 +++ bdk/libs/lvgl/lv_objx/lv_cb.h | 174 ++ bdk/libs/lvgl/lv_objx/lv_chart.c | 824 +++++++ bdk/libs/lvgl/lv_objx/lv_chart.h | 262 +++ bdk/libs/lvgl/lv_objx/lv_cont.c | 642 ++++++ bdk/libs/lvgl/lv_objx/lv_cont.h | 163 ++ bdk/libs/lvgl/lv_objx/lv_ddlist.c | 981 ++++++++ bdk/libs/lvgl/lv_objx/lv_ddlist.h | 286 +++ bdk/libs/lvgl/lv_objx/lv_gauge.c | 466 ++++ bdk/libs/lvgl/lv_objx/lv_gauge.h | 222 ++ bdk/libs/lvgl/lv_objx/lv_img.c | 408 ++++ bdk/libs/lvgl/lv_objx/lv_img.h | 195 ++ bdk/libs/lvgl/lv_objx/lv_imgbtn.c | 391 ++++ bdk/libs/lvgl/lv_objx/lv_imgbtn.h | 249 +++ bdk/libs/lvgl/lv_objx/lv_kb.c | 488 ++++ bdk/libs/lvgl/lv_objx/lv_kb.h | 216 ++ bdk/libs/lvgl/lv_objx/lv_label.c | 987 ++++++++ bdk/libs/lvgl/lv_objx/lv_label.h | 295 +++ bdk/libs/lvgl/lv_objx/lv_led.c | 244 ++ bdk/libs/lvgl/lv_objx/lv_led.h | 116 + bdk/libs/lvgl/lv_objx/lv_line.c | 301 +++ bdk/libs/lvgl/lv_objx/lv_line.h | 158 ++ bdk/libs/lvgl/lv_objx/lv_list.c | 1052 +++++++++ bdk/libs/lvgl/lv_objx/lv_list.h | 336 +++ bdk/libs/lvgl/lv_objx/lv_lmeter.c | 382 ++++ bdk/libs/lvgl/lv_objx/lv_lmeter.h | 153 ++ bdk/libs/lvgl/lv_objx/lv_mbox.c | 532 +++++ bdk/libs/lvgl/lv_objx/lv_mbox.h | 221 ++ bdk/libs/lvgl/lv_objx/lv_objx.mk | 36 + bdk/libs/lvgl/lv_objx/lv_objx_templ.c | 231 ++ bdk/libs/lvgl/lv_objx/lv_objx_templ.h | 111 + bdk/libs/lvgl/lv_objx/lv_page.c | 1205 ++++++++++ bdk/libs/lvgl/lv_objx/lv_page.h | 402 ++++ bdk/libs/lvgl/lv_objx/lv_preload.c | 411 ++++ bdk/libs/lvgl/lv_objx/lv_preload.h | 168 ++ bdk/libs/lvgl/lv_objx/lv_roller.c | 582 +++++ bdk/libs/lvgl/lv_objx/lv_roller.h | 224 ++ bdk/libs/lvgl/lv_objx/lv_slider.c | 520 +++++ bdk/libs/lvgl/lv_objx/lv_slider.h | 202 ++ bdk/libs/lvgl/lv_objx/lv_spinbox.c | 471 ++++ bdk/libs/lvgl/lv_objx/lv_spinbox.h | 201 ++ bdk/libs/lvgl/lv_objx/lv_sw.c | 445 ++++ bdk/libs/lvgl/lv_objx/lv_sw.h | 194 ++ bdk/libs/lvgl/lv_objx/lv_ta.c | 1365 +++++++++++ bdk/libs/lvgl/lv_objx/lv_ta.h | 390 ++++ bdk/libs/lvgl/lv_objx/lv_table.c | 855 +++++++ bdk/libs/lvgl/lv_objx/lv_table.h | 261 +++ bdk/libs/lvgl/lv_objx/lv_tabview.c | 909 ++++++++ bdk/libs/lvgl/lv_objx/lv_tabview.h | 252 +++ bdk/libs/lvgl/lv_objx/lv_tileview.c | 578 +++++ bdk/libs/lvgl/lv_objx/lv_tileview.h | 163 ++ bdk/libs/lvgl/lv_objx/lv_win.c | 591 +++++ bdk/libs/lvgl/lv_objx/lv_win.h | 298 +++ bdk/libs/lvgl/lv_themes/lv_theme.c | 112 + bdk/libs/lvgl/lv_themes/lv_theme.h | 343 +++ bdk/libs/lvgl/lv_themes/lv_theme_hekate.c | 909 ++++++++ bdk/libs/lvgl/lv_themes/lv_theme_hekate.h | 71 + bdk/libs/lvgl/lv_themes/lv_themes.mk | 9 + bdk/libs/lvgl/lv_version.h | 66 + bdk/libs/lvgl/lvgl.h | 85 + bdk/libs/lvgl/lvgl.mk | 8 + {source => bdk}/mem/emc.h | 0 {source => bdk}/mem/heap.c | 9 +- common/common_heap.h => bdk/mem/heap.h | 20 +- {source => bdk}/mem/mc.c | 25 +- source/mem/heap.h => bdk/mem/mc.h | 20 +- {source => bdk}/mem/mc_t210.h | 0 {source => bdk}/mem/minerva.c | 51 +- {source => bdk}/mem/minerva.h | 2 +- {source => bdk}/mem/mtc_table.h | 2 +- {source => bdk}/mem/sdram.c | 41 +- {source => bdk}/mem/sdram.h | 4 +- {source => bdk}/mem/sdram_config.inl | 31 +- {source => bdk}/mem/sdram_config_lz.inl | 0 {source => bdk}/mem/sdram_lp0.c | 6 +- {source => bdk}/mem/sdram_lp0_param_t210.h | 2 +- {source => bdk}/mem/sdram_param_t210.h | 1 - {source/soc => bdk/mem}/smmu.c | 14 +- {source/soc => bdk/mem}/smmu.h | 2 +- {common => bdk}/memory_map.h | 5 +- common/common_module.h => bdk/module.h | 16 +- bdk/power/bq24193.c | 178 ++ bdk/power/bq24193.h | 121 + {source => bdk}/power/max17050.c | 64 +- {source => bdk}/power/max17050.h | 2 +- {source => bdk}/power/max77620.h | 0 {source => bdk}/power/max7762x.c | 8 +- {source => bdk}/power/max7762x.h | 4 +- bdk/power/regulator_5v.c | 76 + .../common_gfx.h => bdk/power/regulator_5v.h | 46 +- {source => bdk}/rtc/max77620-rtc.c | 50 +- {source => bdk}/rtc/max77620-rtc.h | 4 +- {source => bdk}/sec/se.c | 85 +- {source => bdk}/sec/se.h | 10 +- {source => bdk}/sec/se_t210.h | 2 +- {source => bdk}/sec/tsec.c | 36 +- {source => bdk}/sec/tsec.h | 2 +- {source => bdk}/sec/tsec_t210.h | 0 {source => bdk}/soc/bpmp.c | 10 +- {source => bdk}/soc/bpmp.h | 2 +- source/soc/cluster.c => bdk/soc/ccplex.c | 32 +- source/soc/cluster.h => bdk/soc/ccplex.h | 8 +- {source => bdk}/soc/clock.c | 91 +- {source => bdk}/soc/clock.h | 2 +- {source => bdk}/soc/fuse.c | 12 +- {source => bdk}/soc/fuse.h | 3 +- {source => bdk}/soc/gpio.c | 18 +- {source => bdk}/soc/gpio.h | 2 +- {source => bdk}/soc/hw_init.c | 84 +- {source => bdk}/soc/hw_init.h | 2 +- {source => bdk}/soc/i2c.c | 4 +- {source => bdk}/soc/i2c.h | 2 +- {source => bdk}/soc/irq.c | 6 +- {source => bdk}/soc/irq.h | 2 +- {source => bdk}/soc/kfuse.c | 13 +- {source => bdk}/soc/kfuse.h | 2 +- {source => bdk}/soc/pinmux.c | 4 +- {source => bdk}/soc/pinmux.h | 2 +- {source => bdk}/soc/pmc.h | 0 {source => bdk}/soc/pmc_lp0_t210.h | 2 +- {source => bdk}/soc/t210.h | 4 +- bdk/soc/uart.c | 169 ++ bdk/soc/uart.h | 87 + {source => bdk}/storage/mbr_gpt.h | 2 +- {source => bdk}/storage/mmc.h | 0 {source => bdk}/storage/nx_sd.h | 18 +- bdk/storage/ramdisk.c | 67 + bdk/storage/ramdisk.h | 30 + {source => bdk}/storage/sd.h | 6 +- {source => bdk}/storage/sdmmc.c | 27 +- {source => bdk}/storage/sdmmc.h | 4 +- {source => bdk}/storage/sdmmc_driver.c | 73 +- {source => bdk}/storage/sdmmc_driver.h | 4 +- {source => bdk}/storage/sdmmc_t210.h | 2 +- bdk/thermal/fan.c | 106 + bdk/thermal/fan.h | 29 + bdk/thermal/tmp451.c | 65 + bdk/thermal/tmp451.h | 42 + bdk/usb/usb_descriptors.h | 752 +++++++ bdk/usb/usb_gadget_hid.c | 432 ++++ bdk/usb/usb_gadget_ums.c | 1891 ++++++++++++++++ bdk/usb/usb_t210.h | 172 ++ bdk/usb/usbd.c | 1667 ++++++++++++++ bdk/usb/usbd.h | 86 + {source => bdk}/utils/aarch64_util.h | 2 +- {source => bdk}/utils/btn.c | 26 +- {source => bdk}/utils/btn.h | 3 +- {source => bdk}/utils/dirlist.c | 24 +- {source => bdk}/utils/dirlist.h | 4 +- {source/config => bdk/utils}/ini.c | 8 +- {source/config => bdk/utils}/ini.h | 4 +- {source => bdk}/utils/list.h | 2 +- {source => bdk}/utils/sprintf.c | 0 {source => bdk}/utils/sprintf.h | 0 {source => bdk}/utils/types.h | 15 - {source => bdk}/utils/util.c | 43 +- {source => bdk}/utils/util.h | 9 +- source/{config => }/config.c | 24 +- source/{config => }/config.h | 3 +- source/gfx/gfx.c | 20 +- source/gfx/gfx.h | 32 +- source/gfx/tui.c | 32 +- source/gfx/tui.h | 4 +- source/hos/fss.c | 11 +- source/hos/hos.h | 30 +- source/hos/pkg1.c | 2 +- source/hos/pkg1.h | 2 +- source/hos/pkg2.c | 10 +- source/hos/pkg2.h | 7 +- source/hos/sept.c | 31 +- source/hos/sept.h | 2 +- source/keys/key_sources.inl | 2 +- source/keys/keys.c | 198 +- source/keys/save.c | 21 +- source/keys/save.h | 57 +- source/libs/fatfs/diskio.c | 209 +- source/libs/fatfs/ffconf.h | 7 +- source/libs/fatfs/ffsystem.c | 4 +- source/main.c | 52 +- source/mem/mc.h | 14 - source/storage/emummc.c | 87 +- source/storage/emummc.h | 7 +- source/storage/nx_emmc.c | 10 +- source/storage/nx_emmc.h | 13 +- source/storage/nx_emmc_bis.c | 254 +++ source/storage/nx_emmc_bis.h | 231 ++ source/storage/nx_sd.c | 63 +- 317 files changed, 60891 insertions(+), 1003 deletions(-) create mode 100644 bdk/exception_handlers.S create mode 100644 bdk/fatfs_cfg.h rename {source => bdk}/gfx/di.c (76%) rename {source => bdk}/gfx/di.h (98%) rename {source => bdk}/gfx/di.inl (81%) create mode 100644 bdk/gfx_utils.h rename {source/libs => bdk/ianos}/elfload/elf.h (100%) rename {source/libs => bdk/ianos}/elfload/elfarch.h (100%) rename {source/libs => bdk/ianos}/elfload/elfload.c (100%) rename {source/libs => bdk/ianos}/elfload/elfload.h (98%) rename {source/libs => bdk/ianos}/elfload/elfreloc_aarch64.c (100%) rename {source/libs => bdk/ianos}/elfload/elfreloc_arm.c (100%) rename {source => bdk}/ianos/ianos.c (84%) rename {source => bdk}/ianos/ianos.h (89%) create mode 100644 bdk/input/als.c create mode 100644 bdk/input/als.h create mode 100644 bdk/input/joycon.c create mode 100644 bdk/input/joycon.h create mode 100644 bdk/input/touch.c create mode 100644 bdk/input/touch.h rename {source => bdk}/libs/compr/blz.c (100%) rename {source => bdk}/libs/compr/blz.h (97%) rename {source => bdk}/libs/compr/lz.c (100%) rename {source => bdk}/libs/compr/lz.h (100%) rename {source => bdk}/libs/fatfs/diskio.h (95%) rename {source => bdk}/libs/fatfs/ff.c (100%) rename {source => bdk}/libs/fatfs/ff.h (99%) rename {source => bdk}/libs/fatfs/ffunicode.c (100%) create mode 100644 bdk/libs/lv_conf.h create mode 100644 bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md create mode 100644 bdk/libs/lvgl/docs/CONTRIBUTING.md create mode 100644 bdk/libs/lvgl/docs/astyle_c create mode 100644 bdk/libs/lvgl/docs/astyle_h create mode 100644 bdk/libs/lvgl/licence.txt create mode 100644 bdk/libs/lvgl/lv_core/lv_core.mk create mode 100644 bdk/libs/lvgl/lv_core/lv_group.c create mode 100644 bdk/libs/lvgl/lv_core/lv_group.h create mode 100644 bdk/libs/lvgl/lv_core/lv_indev.c create mode 100644 bdk/libs/lvgl/lv_core/lv_indev.h create mode 100644 bdk/libs/lvgl/lv_core/lv_lang.c create mode 100644 bdk/libs/lvgl/lv_core/lv_lang.h create mode 100644 bdk/libs/lvgl/lv_core/lv_obj.c create mode 100644 bdk/libs/lvgl/lv_core/lv_obj.h create mode 100644 bdk/libs/lvgl/lv_core/lv_refr.c create mode 100644 bdk/libs/lvgl/lv_core/lv_refr.h create mode 100644 bdk/libs/lvgl/lv_core/lv_style.c create mode 100644 bdk/libs/lvgl/lv_core/lv_style.h create mode 100644 bdk/libs/lvgl/lv_core/lv_vdb.c create mode 100644 bdk/libs/lvgl/lv_core/lv_vdb.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw.mk create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_arc.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_arc.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_img.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_img.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_label.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_label.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_line.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_line.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_rect.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_rect.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_triangle.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_triangle.h create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c create mode 100644 bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h create mode 100644 bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c create mode 100644 bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c create mode 100644 bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c create mode 100644 bdk/libs/lvgl/lv_fonts/interui_20.c create mode 100644 bdk/libs/lvgl/lv_fonts/interui_30.c create mode 100644 bdk/libs/lvgl/lv_fonts/lv_font_builtin.c create mode 100644 bdk/libs/lvgl/lv_fonts/lv_font_builtin.h create mode 100644 bdk/libs/lvgl/lv_fonts/lv_fonts.mk create mode 100644 bdk/libs/lvgl/lv_fonts/ubuntu_mono.c create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal.h create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal.mk create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_disp.c create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_disp.h create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_indev.c create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_indev.h create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_tick.c create mode 100644 bdk/libs/lvgl/lv_hal/lv_hal_tick.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_anim.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_anim.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_area.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_area.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_circ.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_circ.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_color.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_color.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_font.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_font.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_fs.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_fs.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_gc.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_gc.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_ll.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_ll.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_log.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_log.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_math.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_math.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_mem.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_mem.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_misc.mk create mode 100644 bdk/libs/lvgl/lv_misc/lv_symbol_def.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_task.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_task.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_templ.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_templ.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_txt.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_txt.h create mode 100644 bdk/libs/lvgl/lv_misc/lv_ufs.c create mode 100644 bdk/libs/lvgl/lv_misc/lv_ufs.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_arc.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_arc.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_bar.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_bar.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_btn.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_btn.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_btnm.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_btnm.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_calendar.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_calendar.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_canvas.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_canvas.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_cb.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_cb.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_chart.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_chart.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_cont.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_cont.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_ddlist.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_ddlist.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_gauge.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_gauge.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_img.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_img.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_imgbtn.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_imgbtn.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_kb.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_kb.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_label.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_label.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_led.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_led.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_line.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_line.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_list.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_list.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_lmeter.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_lmeter.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_mbox.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_mbox.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_objx.mk create mode 100644 bdk/libs/lvgl/lv_objx/lv_objx_templ.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_objx_templ.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_page.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_page.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_preload.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_preload.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_roller.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_roller.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_slider.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_slider.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_spinbox.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_spinbox.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_sw.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_sw.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_ta.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_ta.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_table.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_table.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_tabview.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_tabview.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_tileview.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_tileview.h create mode 100644 bdk/libs/lvgl/lv_objx/lv_win.c create mode 100644 bdk/libs/lvgl/lv_objx/lv_win.h create mode 100644 bdk/libs/lvgl/lv_themes/lv_theme.c create mode 100644 bdk/libs/lvgl/lv_themes/lv_theme.h create mode 100644 bdk/libs/lvgl/lv_themes/lv_theme_hekate.c create mode 100644 bdk/libs/lvgl/lv_themes/lv_theme_hekate.h create mode 100644 bdk/libs/lvgl/lv_themes/lv_themes.mk create mode 100644 bdk/libs/lvgl/lv_version.h create mode 100644 bdk/libs/lvgl/lvgl.h create mode 100644 bdk/libs/lvgl/lvgl.mk rename {source => bdk}/mem/emc.h (100%) rename {source => bdk}/mem/heap.c (97%) rename common/common_heap.h => bdk/mem/heap.h (74%) rename {source => bdk}/mem/mc.c (88%) rename source/mem/heap.h => bdk/mem/mc.h (68%) rename {source => bdk}/mem/mc_t210.h (100%) rename {source => bdk}/mem/minerva.c (68%) rename {source => bdk}/mem/minerva.h (98%) rename {source => bdk}/mem/mtc_table.h (99%) rename {source => bdk}/mem/sdram.c (98%) rename {source => bdk}/mem/sdram.h (94%) rename {source => bdk}/mem/sdram_config.inl (98%) rename {source => bdk}/mem/sdram_config_lz.inl (100%) rename {source => bdk}/mem/sdram_lp0.c (99%) rename {source => bdk}/mem/sdram_lp0_param_t210.h (99%) rename {source => bdk}/mem/sdram_param_t210.h (99%) rename {source/soc => bdk/mem}/smmu.c (94%) rename {source/soc => bdk/mem}/smmu.h (99%) rename {common => bdk}/memory_map.h (96%) rename common/common_module.h => bdk/module.h (86%) create mode 100644 bdk/power/bq24193.c create mode 100644 bdk/power/bq24193.h rename {source => bdk}/power/max17050.c (81%) rename {source => bdk}/power/max17050.h (99%) rename {source => bdk}/power/max77620.h (100%) rename {source => bdk}/power/max7762x.c (98%) rename {source => bdk}/power/max7762x.h (98%) create mode 100644 bdk/power/regulator_5v.c rename common/common_gfx.h => bdk/power/regulator_5v.h (57%) rename {source => bdk}/rtc/max77620-rtc.c (81%) rename {source => bdk}/rtc/max77620-rtc.h (95%) rename {source => bdk}/sec/se.c (90%) rename {source => bdk}/sec/se.h (85%) rename {source => bdk}/sec/se_t210.h (99%) rename {source => bdk}/sec/tsec.c (93%) rename {source => bdk}/sec/tsec.h (97%) rename {source => bdk}/sec/tsec_t210.h (100%) rename {source => bdk}/soc/bpmp.c (98%) rename {source => bdk}/soc/bpmp.h (98%) rename source/soc/cluster.c => bdk/soc/ccplex.c (88%) rename source/soc/cluster.h => bdk/soc/ccplex.h (86%) rename {source => bdk}/soc/clock.c (89%) rename {source => bdk}/soc/clock.h (99%) rename {source => bdk}/soc/fuse.c (96%) rename {source => bdk}/soc/fuse.h (97%) rename {source => bdk}/soc/gpio.c (91%) rename {source => bdk}/soc/gpio.h (98%) rename {source => bdk}/soc/hw_init.c (90%) rename {source => bdk}/soc/hw_init.h (96%) rename {source => bdk}/soc/i2c.c (98%) rename {source => bdk}/soc/i2c.h (98%) rename {source => bdk}/soc/irq.c (98%) rename {source => bdk}/soc/irq.h (99%) rename {source => bdk}/soc/kfuse.c (87%) rename {source => bdk}/soc/kfuse.h (97%) rename {source => bdk}/soc/pinmux.c (95%) rename {source => bdk}/soc/pinmux.h (99%) rename {source => bdk}/soc/pmc.h (100%) rename {source => bdk}/soc/pmc_lp0_t210.h (99%) rename {source => bdk}/soc/t210.h (98%) create mode 100644 bdk/soc/uart.c create mode 100644 bdk/soc/uart.h rename {source => bdk}/storage/mbr_gpt.h (98%) rename {source => bdk}/storage/mmc.h (100%) rename {source => bdk}/storage/nx_sd.h (78%) create mode 100644 bdk/storage/ramdisk.c create mode 100644 bdk/storage/ramdisk.h rename {source => bdk}/storage/sd.h (98%) rename {source => bdk}/storage/sdmmc.c (98%) rename {source => bdk}/storage/sdmmc.h (97%) rename {source => bdk}/storage/sdmmc_driver.c (95%) rename {source => bdk}/storage/sdmmc_driver.h (99%) rename {source => bdk}/storage/sdmmc_t210.h (98%) create mode 100644 bdk/thermal/fan.c create mode 100644 bdk/thermal/fan.h create mode 100644 bdk/thermal/tmp451.c create mode 100644 bdk/thermal/tmp451.h create mode 100644 bdk/usb/usb_descriptors.h create mode 100644 bdk/usb/usb_gadget_hid.c create mode 100644 bdk/usb/usb_gadget_ums.c create mode 100644 bdk/usb/usb_t210.h create mode 100644 bdk/usb/usbd.c create mode 100644 bdk/usb/usbd.h rename {source => bdk}/utils/aarch64_util.h (98%) rename {source => bdk}/utils/btn.c (85%) rename {source => bdk}/utils/btn.h (92%) rename {source => bdk}/utils/dirlist.c (82%) rename {source => bdk}/utils/dirlist.h (91%) rename {source/config => bdk/utils}/ini.c (96%) rename {source/config => bdk/utils}/ini.h (95%) rename {source => bdk}/utils/list.h (98%) rename {source => bdk}/utils/sprintf.c (100%) rename {source => bdk}/utils/sprintf.h (100%) rename {source => bdk}/utils/types.h (82%) rename {source => bdk}/utils/util.c (86%) rename {source => bdk}/utils/util.h (92%) rename source/{config => }/config.c (78%) rename source/{config => }/config.h (95%) delete mode 100644 source/mem/mc.h create mode 100644 source/storage/nx_emmc_bis.c create mode 100644 source/storage/nx_emmc_bis.h diff --git a/Makefile b/Makefile index 404fec4..4075925 100644 --- a/Makefile +++ b/Makefile @@ -19,15 +19,26 @@ TARGET := Lockpick_RCM BUILDDIR := build OUTPUTDIR := output SOURCEDIR = source +BDKDIR := bdk +BDKINC := -I./$(BDKDIR) +VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) +VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \ $(call rwildcard, $(SOURCEDIR), *.S *.c))) +OBJS += $(patsubst $(BDKDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ + $(patsubst $(BDKDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \ + $(call rwildcard, $(BDKDIR), *.S *.c))) + +GFX_INC := '"../$(SOURCEDIR)/gfx/gfx.h"' +FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"' ################################################################################ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) +CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fno-inline -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) @@ -47,16 +58,26 @@ $(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf @mkdir -p "$(@D)" $(OBJCOPY) -S -O binary $< $@ @echo -n "Payload size is " - @wc -c < $@ + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) + @echo $(BIN_SIZE) @echo "Max size is 126296 Bytes." + @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.S @mkdir -p "$(@D)" $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c + @mkdir -p "$(@D)" + $(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S + @mkdir -p "$(@D)" + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/bdk/exception_handlers.S b/bdk/exception_handlers.S new file mode 100644 index 0000000..97d1ec6 --- /dev/null +++ b/bdk/exception_handlers.S @@ -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 . + */ + +/* + * 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 | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR + * 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq + * 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq + * 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc + * 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt + * 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und + * 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, 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 diff --git a/bdk/fatfs_cfg.h b/bdk/fatfs_cfg.h new file mode 100644 index 0000000..a12585f --- /dev/null +++ b/bdk/fatfs_cfg.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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 . + */ + +#ifndef _FATFS_CFG_H_ +#define _FATFS_CFG_H_ + +#ifdef FFCFG_INC +#include FFCFG_INC +#endif + +#endif diff --git a/source/gfx/di.c b/bdk/gfx/di.c similarity index 76% rename from source/gfx/di.c rename to bdk/gfx/di.c index 3252475..1549e7b 100644 --- a/source/gfx/di.c +++ b/bdk/gfx/di.c @@ -18,16 +18,15 @@ #include #include "di.h" -#include "../gfx/gfx.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/i2c.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "di.inl" @@ -145,13 +144,13 @@ void display_init() // Decode Display ID. _display_id = ((_display_id >> 8) & 0xFF00) | (_display_id & 0xFF); - if ((_display_id & 0xFF) == PANEL_JDI_LPM062M) - _display_id = PANEL_JDI_LPM062M; + if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) + _display_id = PANEL_JDI_XXX062M; // Initialize display panel. switch (_display_id) { - case PANEL_JDI_LPM062M: + case PANEL_JDI_XXX062M: exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); break; @@ -264,7 +263,7 @@ void display_end() // De-initialize display panel. switch (_display_id) { - case PANEL_JDI_LPM062M: + case PANEL_JDI_XXX062M: exec_cfg((u32 *)DSI_BASE, _display_deinit_config_jdi, 22); break; case PANEL_AUO_A062TAN01: @@ -337,15 +336,111 @@ void display_color_screen(u32 color) display_backlight(true); } -u32 *display_init_framebuffer() +u32 *display_init_framebuffer_pitch() { // Sanitize framebuffer area. memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000); // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch, 32); usleep(35000); return (u32 *)IPL_FB_ADDRESS; } +u32 *display_init_framebuffer_pitch_inv() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch_inv, 34); + + usleep(35000); + + return (u32 *)NYX_FB_ADDRESS; +} + +u32 *display_init_framebuffer_block() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_block, 34); + + usleep(35000); + + return (u32 *)NYX_FB_ADDRESS; +} + +u32 *display_init_framebuffer_log() +{ + // This configures the framebuffer @ LOG_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_log, 20); + + return (u32 *)LOG_FB_ADDRESS; +} + +void display_activate_console() +{ + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = WIN_ENABLE; // Enable window DD. + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0xFF80; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + + for (u32 i = 0xFF80; i < 0x10000; i++) + { + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(1000); + } + + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_deactivate_console() +{ + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + + for (u32 i = 0xFFFF; i > 0xFF7F; i--) + { + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(500); + } + + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0; // Disable window DD. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_init_cursor(void *crs_fb, u32 size) +{ + // Setup cursor. + DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10); + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = + CURSOR_BLEND_R8G8B8A8 | CURSOR_BLEND_DST_FACTOR(CURSOR_BLEND_K1) | CURSOR_BLEND_SRC_FACTOR(CURSOR_BLEND_K1) | 0xFF; + + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) |= CURSOR_ENABLE; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_set_pos_cursor(u32 x, u32 y) +{ + DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16); + + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_deinit_cursor() +{ + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = 0; + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} diff --git a/source/gfx/di.h b/bdk/gfx/di.h similarity index 98% rename from source/gfx/di.h rename to bdk/gfx/di.h index a160eff..2723de0 100644 --- a/source/gfx/di.h +++ b/bdk/gfx/di.h @@ -18,8 +18,8 @@ #ifndef _DI_H_ #define _DI_H_ -#include "../../common/memory_map.h" -#include "../utils/types.h" +#include +#include /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) @@ -506,7 +506,9 @@ enum { - PANEL_JDI_LPM062M = 0x10, + PANEL_JDI_XXX062M = 0x10, + PANEL_JDI_LAM062M109A = 0x0910, + PANEL_JDI_LPM062M326A = 0x2610, PANEL_INL_P062CCA_AZ1 = 0x0F20, PANEL_AUO_A062TAN01 = 0x0F30, PANEL_INL_P062CCA_AZ2 = 0x1020, @@ -525,7 +527,12 @@ void display_backlight(bool enable); void display_backlight_brightness(u32 brightness, u32 step_delay); /*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ -u32 *display_init_framebuffer(); +u32 *display_init_framebuffer_pitch(); +u32 *display_init_framebuffer_pitch_inv(); +u32 *display_init_framebuffer_block(); +u32 *display_init_framebuffer_log(); +void display_activate_console(); +void display_deactivate_console(); void display_init_cursor(void *crs_fb, u32 size); void display_set_pos_cursor(u32 x, u32 y); void display_deinit_cursor(); diff --git a/source/gfx/di.inl b/bdk/gfx/di.inl similarity index 81% rename from source/gfx/di.inl rename to bdk/gfx/di.inl index 9a275eb..ef3b1b0 100644 --- a/source/gfx/di.inl +++ b/bdk/gfx/di.inl @@ -559,8 +559,8 @@ static const cfg_op_t cfg_display_one_color[8] = { {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display. }; -//Display A config. -static const cfg_op_t cfg_display_framebuffer[32] = { +//Display A config linear pitch. +static const cfg_op_t cfg_display_framebuffer_pitch[32] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, @@ -568,14 +568,14 @@ static const cfg_op_t cfg_display_framebuffer[32] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_POSITION, 0}, //(0,0) {DC_WIN_H_INITIAL_DDA, 0}, {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, @@ -594,3 +594,103 @@ static const cfg_op_t cfg_display_framebuffer[32] = { {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} }; + +//Display A config linear pitch inverse + Win D support. +static const cfg_op_t cfg_display_framebuffer_pitch_inv[34] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, // Linear: 0x383FFC, Block: 0x3813FC. + {DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +//Display A config block linear. +static const cfg_op_t cfg_display_framebuffer_block[34] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, // Linear: 0x383FFC, Block: 0x3813FC. + {DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, // Enable window AD. | SCAN_COLUMN | H_DIRECTION. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +//Display D config. +static const cfg_op_t cfg_display_framebuffer_log[20] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(656 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(656)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(656 * 2) | LINE_STRIDE(656 * 4)}, //656*2x656*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, LOG_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, + {DC_WINBUF_ADDR_V_OFFSET, 0}, + {DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200)}, + {DC_WINBUF_BLEND_MATCH_SELECT, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1}, + {DC_WIN_WIN_OPTIONS, 0}, // Enable window DD. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ} +}; diff --git a/bdk/gfx_utils.h b/bdk/gfx_utils.h new file mode 100644 index 0000000..ca81a7f --- /dev/null +++ b/bdk/gfx_utils.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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 . + */ + +#ifndef _GFX_UTILS_H_ +#define _GFX_UTILS_H_ + +#ifdef GFX_INC +#include GFX_INC +#endif + +#endif diff --git a/source/libs/elfload/elf.h b/bdk/ianos/elfload/elf.h similarity index 100% rename from source/libs/elfload/elf.h rename to bdk/ianos/elfload/elf.h diff --git a/source/libs/elfload/elfarch.h b/bdk/ianos/elfload/elfarch.h similarity index 100% rename from source/libs/elfload/elfarch.h rename to bdk/ianos/elfload/elfarch.h diff --git a/source/libs/elfload/elfload.c b/bdk/ianos/elfload/elfload.c similarity index 100% rename from source/libs/elfload/elfload.c rename to bdk/ianos/elfload/elfload.c diff --git a/source/libs/elfload/elfload.h b/bdk/ianos/elfload/elfload.h similarity index 98% rename from source/libs/elfload/elfload.h rename to bdk/ianos/elfload/elfload.h index 3a15dc2..2b9bb67 100644 --- a/source/libs/elfload/elfload.h +++ b/bdk/ianos/elfload/elfload.h @@ -22,10 +22,10 @@ #include "elfarch.h" #include "elf.h" -#include "../../utils/types.h" +#include #ifdef DEBUG -#include "../../gfx/gfx.h" +#include #define EL_DEBUG(format, ...) \ gfx_printf(format __VA_OPT__(, ) __VA_ARGS__) #else diff --git a/source/libs/elfload/elfreloc_aarch64.c b/bdk/ianos/elfload/elfreloc_aarch64.c similarity index 100% rename from source/libs/elfload/elfreloc_aarch64.c rename to bdk/ianos/elfload/elfreloc_aarch64.c diff --git a/source/libs/elfload/elfreloc_arm.c b/bdk/ianos/elfload/elfreloc_arm.c similarity index 100% rename from source/libs/elfload/elfreloc_arm.c rename to bdk/ianos/elfload/elfreloc_arm.c diff --git a/source/ianos/ianos.c b/bdk/ianos/ianos.c similarity index 84% rename from source/ianos/ianos.c rename to bdk/ianos/ianos.c index 85ac9c9..5eca1b6 100644 --- a/source/ianos/ianos.c +++ b/bdk/ianos/ianos.c @@ -18,12 +18,13 @@ #include #include "ianos.h" -#include "../../common/common_module.h" -#include "../gfx/gfx.h" -#include "../libs/elfload/elfload.h" -#include "../mem/heap.h" -#include "../storage/nx_sd.h" -#include "../utils/types.h" +#include "elfload/elfload.h" +#include +#include +#include +#include + +#include #define IRAM_LIB_ADDR 0x4002B000 #define DRAM_LIB_ADDR 0xE0000000 @@ -36,8 +37,8 @@ void *fileBuf = NULL; static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) { bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t)); - bdkParameters->gfxCon = &gfx_con; - bdkParameters->gfxCtx = &gfx_ctxt; + bdkParameters->gfxCon = (void *)&gfx_con; + bdkParameters->gfxCtx = (void *)&gfx_ctxt; bdkParameters->memcpy = (memcpy_t)&memcpy; bdkParameters->memset = (memset_t)&memset; bdkParameters->sharedHeap = &_heap; @@ -63,26 +64,20 @@ static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t o } //TODO: Support shared libraries. -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig) +uintptr_t ianos_loader(char *path, elfType_t type, void *moduleConfig) { + el_ctx ctx; uintptr_t epaddr = 0; - if (sdmount) - { - if (!sd_mount()) - goto elfLoadFinalOut; - } + if (!sd_mount()) + goto elfLoadFinalOut; + // Read library. fileBuf = sd_file_read(path, NULL); - if (sdmount) - sd_unmount(); - if (!fileBuf) goto elfLoadFinalOut; - - el_ctx ctx; ctx.pread = _ianos_read_cb; if (el_init(&ctx)) @@ -94,7 +89,6 @@ uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleCon case EXEC_ELF: case AR64_ELF: elfBuf = (void *)DRAM_LIB_ADDR; - sd_unmount(); break; default: elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default. @@ -123,6 +117,5 @@ elfFreeOut: fileBuf = NULL; elfLoadFinalOut: - return epaddr; } \ No newline at end of file diff --git a/source/ianos/ianos.h b/bdk/ianos/ianos.h similarity index 89% rename from source/ianos/ianos.h rename to bdk/ianos/ianos.h index 74d02c1..5ebec64 100644 --- a/source/ianos/ianos.h +++ b/bdk/ianos/ianos.h @@ -18,7 +18,7 @@ #ifndef IANOS_H #define IANOS_H -#include "../utils/types.h" +#include typedef enum { @@ -29,6 +29,6 @@ typedef enum KEEP_IN_RAM = (1 << 31) // Shared library mask. } elfType_t; -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config); +uintptr_t ianos_loader(char *path, elfType_t type, void* config); #endif \ No newline at end of file diff --git a/bdk/input/als.c b/bdk/input/als.c new file mode 100644 index 0000000..99749e2 --- /dev/null +++ b/bdk/input/als.c @@ -0,0 +1,118 @@ +/* + * 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 . + */ + +#include "als.h" +#include +#include +#include +#include +#include +#include + +#define HOS_GAIN BH1730_GAIN_64X +#define HOS_ITIME 38 + +void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime) +{ + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime)); + + als_val->gain = gain; + als_val->itime = itime; +} + +void get_als_lux(als_table_t *als_val) +{ + u32 data[2]; + float pre_gain_lux; + float visible_light; + float ir_light; + float light_ratio; + + u8 adc_ready = 0; + u8 retries = 100; + + const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 }; + const float als_norm_res = 100.0; + const float als_multiplier = 3.6; + const float als_tint = 2.7; + + // Wait for ADC to prepare new data. + while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries) + { + retries--; + adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG)); + } + + // Get visible and ir light raw data. + data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); + data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); + + als_val->over_limit = data[0] > 65534 || data[1] > 65534; + als_val->vi_light = data[0]; + als_val->ir_light = data[1]; + + if (!data[0] || !retries) + { + als_val->lux = 0.0; + + return; + } + + visible_light = (float)data[0]; + ir_light = (float)data[1]; + light_ratio = (float)data[1] / (float)data[0]; + + // The following are specific to the light filter Switch uses. + if (light_ratio < 0.5) + pre_gain_lux = visible_light * 5.002 - ir_light * 7.502; + else if (light_ratio < 0.754) + pre_gain_lux = visible_light * 2.250 - ir_light * 2.000; + else if (light_ratio < 1.029) + pre_gain_lux = visible_light * 1.999 - ir_light * 1.667; + else if (light_ratio < 1.373) + pre_gain_lux = visible_light * 0.884 - ir_light * 0.583; + else if (light_ratio < 1.879) + pre_gain_lux = visible_light * 0.309 - ir_light * 0.165; + else pre_gain_lux = 0.0; + + als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier; +} + +u8 als_init(als_table_t *als_val) +{ + pinmux_config_i2c(I2C_2); + clock_enable_i2c(I2C_2); + i2c_init(I2C_2); + + max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD8 | MAX77620_LDO_CFG2_ADE_MASK); + + u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME)); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); + + als_val->gain = HOS_GAIN; + als_val->itime = HOS_ITIME; + + return id; +} diff --git a/bdk/input/als.h b/bdk/input/als.h new file mode 100644 index 0000000..ad31e42 --- /dev/null +++ b/bdk/input/als.h @@ -0,0 +1,65 @@ +/* + * 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 . + */ + +#ifndef __ALS_H_ +#define __ALS_H_ + +#include + +#define BH1730_I2C_ADDR 0x29 + +#define BH1730_CMD_MAGIC 0x80 +#define BH1730_CMD_SETADDR 0x00 +#define BH1730_CMD_SPECCMD 0x60 +#define BH1730_SPECCMD_RESET 0x4 + +#define BH1730_CONTROL_REG 0x00 +#define BH1730_CTL_ADC_VALID 0x10 +#define BH1730_CTL_ONE_TIME 0x08 +#define BH1730_CTL_DAT0_ONLY 0x04 +#define BH1730_CTL_ADC_EN 0x02 +#define BH1730_CTL_POWER_ON 0x01 +#define BH1730_TIMING_REG 0x01 +#define BH1730_GAIN_REG 0x07 +#define BH1730_GAIN_1X 0x00 +#define BH1730_GAIN_2X 0x01 +#define BH1730_GAIN_64X 0x02 +#define BH1730_GAIN_128X 0x03 +#define BH1730_DATA0LOW_REG 0x14 +#define BH1730_DATA0HIGH_REG 0x15 +#define BH1730_DATA1LOW_REG 0x16 +#define BH1730_DATA1HIGH_REG 0x17 + +#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | reg) +#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | cmd) + +typedef struct _als_table_t +{ + float lux; + bool over_limit; + u32 vi_light; + u32 ir_light; + u8 gain; + u8 itime; +} als_table_t; + +void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime); +void get_als_lux(als_table_t *als_val); +u8 als_init(als_table_t *als_val); + +#endif /* __ALS_H_ */ diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c new file mode 100644 index 0000000..2db1aa6 --- /dev/null +++ b/bdk/input/joycon.c @@ -0,0 +1,872 @@ +/* + * 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 . + */ + +#include + +#include "joycon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// For disabling driver when logging is enabled. +#include + +#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 SPI_READ_OFFSET 0x20 +#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; + + jc_send_hid_output_rpt(uart, (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->size == 0x1A && pair_data->magic == 0x95 && pair_data->size == 0x22) + { + 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, 0x100); + + // 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; +} + +static bool _jc_validate_pairing_info(u8 *buf, bool *is_hos) +{ + u8 crc = 0; + for (u32 i = 0; i < 0x22; i++) + crc += buf[4 + i]; + + crc += 0x68; // Host is Switch. + + if ((crc ^ 0x55) == buf[2]) + *is_hos = true; + + crc -= 0x68; + crc += 0x08; // Host is PC. + + if (*is_hos || (crc ^ 0x55) == buf[2]) + return true; + + return false; +} + +jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos) +{ + 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_l; + subcmd_data_l.addr = 0x2000; + subcmd_data_l.size = 0x1A; + + jc_hid_in_spi_read_t subcmd_data_r; + subcmd_data_r.addr = 0x2000; + subcmd_data_r.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 = 10; +retry: + retries = 10; + while (retries) + { + u32 time_now = get_tmr_ms(); + if ((!jc_l_found && jc_l.last_status_req_time < time_now) || (!jc_r_found && jc_r.last_status_req_time < time_now)) + { + if (!jc_l_found) + { + jc_send_hid_cmd(jc_l.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5); + jc_l.last_status_req_time = get_tmr_ms() + 15; + } + + if (!jc_r_found) + { + jc_send_hid_cmd(jc_r.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5); + jc_r.last_status_req_time = get_tmr_ms() + 15; + } + + retries--; + } + + if (!jc_l_found) + { + memset(jc_l.buf, 0, 0x100); + jc_rcv_pkt(&jc_l); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_l.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_l.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_l.addr += 0x26; // Get next slot. + else + jc_l_found = true; // Entry is active. + + if (jc_l_found && is_hos) + *is_l_hos = true; + } + } + + if (!jc_r_found) + { + memset(jc_r.buf, 0, 0x100); + jc_rcv_pkt(&jc_r); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_r.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_r.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_r.addr += 0x26; // Get next slot. + else + jc_r_found = true; // Entry is active. + + if (jc_r_found && is_hos) + *is_r_hos = true; + } + } + + if (jc_l_found && jc_r_found) + break; + } + + if (!jc_l_found || !jc_r_found) + { + if (total_retries) + { + total_retries--; + goto retry; + } + + if (!jc_l_found) + { + bt_conn = &jc_gamepad.bt_conn_l; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + + if (!jc_r_found) + { + bt_conn = &jc_gamepad.bt_conn_r; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + } + + // 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); + jc_rcv_pkt(&jc_r); + } + if (jc_l.connected) + { + jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 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; +} diff --git a/bdk/input/joycon.h b/bdk/input/joycon.h new file mode 100644 index 0000000..932c836 --- /dev/null +++ b/bdk/input/joycon.h @@ -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 . + */ + +#ifndef __JOYCON_H_ +#define __JOYCON_H_ + +#include + +#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(bool *is_l_hos, bool *is_r_hos); + +#endif \ No newline at end of file diff --git a/bdk/input/touch.c b/bdk/input/touch.c new file mode 100644 index 0000000..eef61ec --- /dev/null +++ b/bdk/input/touch.c @@ -0,0 +1,422 @@ +/* + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller + * + * Copyright (c) 2018 langerhans + * Copyright (c) 2018-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 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "touch.h" + + +#include +#define DPRINTF(...) gfx_printf(__VA_ARGS__) + +static int touch_command(u8 cmd, u8 *buf, u8 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd, buf, size); + if (!res) + return 1; + return 0; +} + +static int touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd[0], &cmd[1], csize - 1); + if (res) + res = i2c_recv_buf(buf, size, I2C_3, STMFTS_I2C_ADDR); + if (!res) + return 1; + + return 0; +} + +static int touch_wait_event(u8 event, u8 status, u32 timeout) +{ + u32 timer = get_tmr_ms() + timeout; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == event && tmp[2] == status) + return 0; + + if (get_tmr_ms() > timer) + return 1; + } +} + +#define X_REAL_MAX 1264 +#define Y_REAL_MAX 704 +#define EDGE_OFFSET 15 + +static void _touch_compensate_limits(touch_event *event, bool touching) +{ + event->x = MAX(event->x, EDGE_OFFSET); + event->x = MIN(event->x, X_REAL_MAX); + event->x -= EDGE_OFFSET; + u32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET); + event->x = ((u32)event->x * x_adj) / 1000; + + if (touching) + { + event->y = MAX(event->y, EDGE_OFFSET); + event->y = MIN(event->y, Y_REAL_MAX); + event->y -= EDGE_OFFSET; + u32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET); + event->y = ((u32)event->y * y_adj) / 1000; + } +} + +static void _touch_process_contact_event(touch_event *event, bool touching) +{ + event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4); + + // Normally, GUI elements have bigger horizontal estate. + // Avoid parsing y axis when finger is removed to minimize touch noise. + if (touching) + { + event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB); + + event->z = event->raw[5] | (event->raw[6] << 8); + event->z = event->z << 6; + u16 tmp = 0x40; + if ((event->raw[7] & 0x3F) != 1 && (event->raw[7] & 0x3F) != 0x3F) + tmp = event->raw[7] & 0x3F; + event->z /= tmp + 0x40; + + event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1; + } + else + event->fingers = 0; + + _touch_compensate_limits(event, touching); +} + +static void _touch_parse_event(touch_event *event) +{ + event->type = event->raw[1] & STMFTS_MASK_EVENT_ID; + + switch (event->type) + { + case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + _touch_process_contact_event(event, true); + if (event->z < 255) // Reject palm rest. + event->touch = true; + else + { + event->touch = false; + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + event->touch = false; + _touch_process_contact_event(event, false); + break; + case STMFTS_EV_NO_EVENT: + if (event->touch) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + break; + default: + if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + else + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + + // gfx_con_setpos(&gfx_con, 0, 300); + // DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z); + // DPRINTF("0 = %02X\n1 = %02x\n2 = %02x\n3 = %02x\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); + // DPRINTF("4 = %02X\n5 = %02x\n6 = %02x\n7 = %02x\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); +} + +void touch_poll(touch_event *event) +{ + i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT); + + _touch_parse_event(event); +} + +touch_event touch_poll_wait() +{ + touch_event event; + do + { + touch_poll(&event); + } while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE); + + return event; +} + +touch_info touch_get_info() +{ + touch_info info; + u8 buf[8]; + memset(&buf, 0, 8); + i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO); + + info.chip_id = buf[0] << 8 | buf[1]; + info.fw_ver = buf[2] << 8 | buf[3]; + info.config_id = buf[4]; + info.config_ver = buf[5]; + + //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02x, Cfg Ver: %d\n", + // info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver); + + return info; +} + +int touch_get_fw_info(touch_fw_info_t *fw) +{ + u8 buf[8] = {0}; + + // Get fw address info. + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0x60 }; + int res = touch_read_reg(cmd, 3, buf, 3); + if (!res) + { + // Get fw info. + cmd[1] = buf[2]; cmd[2] = buf[1]; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + { + fw->fw_id = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4]; + fw->ftb_ver = (buf[6] << 8) | buf[5]; + } + + cmd[2]++; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + fw->fw_rev = (buf[7] << 8) | buf[6]; + } + + return res; +} + +int touch_sys_reset() +{ + u8 cmd[3] = { 0, 0x28, 0x80 }; // System reset cmd. + for (u8 retries = 0; retries < 3; retries++) + { + if (touch_command(STMFTS_WRITE_REG, cmd, 3)) + { + msleep(10); + continue; + } + msleep(10); + if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20)) + continue; + else + return 0; + } + + return 1; +} + +int touch_panel_ito_test(u8 *err) +{ + int res = 0; + + // Reset touchscreen module. + if (touch_sys_reset()) + return res; + + // Do ITO Production test. + u8 cmd[2] = { 1, 0 }; + if (touch_command(STMFTS_ITO_CHECK, cmd, 2)) + return res; + + u32 timer = get_tmr_ms() + 2000; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == 0xF && tmp[2] == 0x5) + { + if (err) + { + err[0] = tmp[3]; + err[1] = tmp[4]; + } + + res = 1; + break; + } + + if (get_tmr_ms() > timer) + break; + } + + // Reset touchscreen module. + touch_sys_reset(); + + return res; +} + +int touch_get_fb_info(u8 *buf) +{ + u8 tmp[5]; + + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0 }; + int res = 0; + + + for (u32 i = 0; i < 0x10000; i+=4) + { + if (!res) + { + cmd[1] = (i >> 8) & 0xFF; + cmd[2] = i & 0xFF; + memset(tmp, 0xCC, 5); + res = touch_read_reg(cmd, 3, tmp, 5); + memcpy(&buf[i], tmp + 1, 4); + } + } + + return res; +} + +int touch_sense_enable() +{ + // Enable auto tuning calibration and multi-touch sensing. + u8 cmd = 1; + if (touch_command(STMFTS_AUTO_CALIBRATION, &cmd, 1)) + return 0; + + if (touch_command(STMFTS_MS_MT_SENSE_ON, NULL, 0)) + return 0; + + if (touch_command(STMFTS_CLEAR_EVENT_STACK, NULL, 0)) + return 0; + + return 1; +} + +int touch_execute_autotune() +{ + // Reset touchscreen module. + if (touch_sys_reset()) + return 0; + + // Trim low power oscillator. + if (touch_command(STMFTS_LP_TIMER_CALIB, NULL, 0)) + return 0; + msleep(200); + + // Apply Mutual Sense Compensation tuning. + if (touch_command(STMFTS_MS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000)) + return 0; + + // Apply Self Sense Compensation tuning. + if (touch_command(STMFTS_SS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000)) + return 0; + + // Save Compensation data to EEPROM. + if (touch_command(STMFTS_SAVE_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000)) + return 0; + + return touch_sense_enable(); +} + +static int touch_init() +{ + // Initialize touchscreen module. + if (touch_sys_reset()) + return 0; + + return touch_sense_enable(); +} + +int touch_power_on() +{ + // Enables LDO6 for touchscreen VDD/AVDD supply + max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, + MAX77620_LDO_CFG2_ADE_ENABLE | (3 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + + // Configure touchscreen GPIO. + PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; + gpio_config(GPIO_PORT_J, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_J, GPIO_PIN_7, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH); + + // IRQ and more. + // PINMUX_AUX(PINMUX_AUX_TOUCH_INT) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 3; + // gpio_config(GPIO_PORT_X, GPIO_PIN_1, GPIO_MODE_GPIO); + // gpio_write(GPIO_PORT_X, GPIO_PIN_1, GPIO_LOW); + + // Configure Touscreen and GCAsic shared GPIO. + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; + gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); + + // Initialize I2C3. + pinmux_config_i2c(I2C_3); + clock_enable_i2c(I2C_3); + i2c_init(I2C_3); + + // Wait for the touchscreen module to get ready. + touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20); + + // Check for forced boot time calibration. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + u8 err[2]; + if (touch_panel_ito_test(err)) + if (!err[0] && !err[1]) + return touch_execute_autotune(); + } + + // Initialize touchscreen. + u32 retries = 3; + while (retries) + { + if (touch_init()) + return 1; + retries--; + } + + return 0; +} + +void touch_power_off() +{ + // Disable touchscreen power. + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); + + // Disables LDO6 for touchscreen VDD, AVDD supply + max77620_regulator_enable(REGULATOR_LDO6, 0); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, + MAX77620_LDO_CFG2_ADE_ENABLE | (2 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + + clock_disable_i2c(I2C_3); +} \ No newline at end of file diff --git a/bdk/input/touch.h b/bdk/input/touch.h new file mode 100644 index 0000000..9245be3 --- /dev/null +++ b/bdk/input/touch.h @@ -0,0 +1,157 @@ +/* + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller + * + * Copyright (c) 2018 langerhans + * Copyright (c) 2018-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 . + */ + +#ifndef __TOUCH_H_ +#define __TOUCH_H_ + +#include + +#define STMFTS_I2C_ADDR 0x49 + +/* I2C commands */ +#define STMFTS_READ_INFO 0x80 +#define STMFTS_READ_STATUS 0x84 +#define STMFTS_READ_ONE_EVENT 0x85 +#define STMFTS_READ_ALL_EVENT 0x86 +#define STMFTS_LATEST_EVENT 0x87 +#define STMFTS_SLEEP_IN 0x90 +#define STMFTS_SLEEP_OUT 0x91 +#define STMFTS_MS_MT_SENSE_OFF 0x92 +#define STMFTS_MS_MT_SENSE_ON 0x93 +#define STMFTS_SS_HOVER_SENSE_OFF 0x94 +#define STMFTS_SS_HOVER_SENSE_ON 0x95 +#define STMFTS_LP_TIMER_CALIB 0x97 +#define STMFTS_MS_KEY_SENSE_OFF 0x9A +#define STMFTS_MS_KEY_SENSE_ON 0x9B +#define STMFTS_SYSTEM_RESET 0xA0 +#define STMFTS_CLEAR_EVENT_STACK 0xA1 +#define STMFTS_FULL_FORCE_CALIBRATION 0xA2 +#define STMFTS_MS_CX_TUNING 0xA3 +#define STMFTS_SS_CX_TUNING 0xA4 +#define STMFTS_ITO_CHECK 0xA7 +#define STMFTS_RELEASEINFO 0xAA +#define STMFTS_WRITE_REG 0xB6 +#define STMFTS_AUTO_CALIBRATION 0xC3 +#define STMFTS_NOISE_WRITE 0xC7 +#define STMFTS_NOISE_READ 0xC8 +#define STMFTS_RW_FRAMEBUFFER_REG 0xD0 +#define STMFTS_SAVE_CX_TUNING 0xFC + +#define STMFTS_UNK0 0xB8 //Request compensation +#define STMFTS_UNK1 0xCF +#define STMFTS_UNK2 0xF7 +#define STMFTS_UNK3 0xFA +#define STMFTS_UNK4 0xF9 +#define STMFTS_UNK5 0x62 + + +/* events */ +#define STMFTS_EV_NO_EVENT 0x00 +#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02 +#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03 +#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04 +#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05 +#define STMFTS_EV_HOVER_ENTER 0x07 +#define STMFTS_EV_HOVER_LEAVE 0x08 +#define STMFTS_EV_HOVER_MOTION 0x09 +#define STMFTS_EV_KEY_STATUS 0x0e +#define STMFTS_EV_ERROR 0x0f +#define STMFTS_EV_NOISE_READ 0x17 +#define STMFTS_EV_NOISE_WRITE 0x18 + +#define STMFTS_EV_CONTROLLER_READY 0x10 +#define STMFTS_EV_STATUS 0x16 +#define STMFTS_EV_DEBUG 0xDB + +#define STMFTS_EV_STATUS_MS_CX_TUNING_DONE 1 +#define STMFTS_EV_STATUS_SS_CX_TUNING_DONE 2 +#define STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE 4 + +/* multi touch related event masks */ +#define STMFTS_MASK_EVENT_ID 0x0F +#define STMFTS_MASK_TOUCH_ID 0xF0 +#define STMFTS_MASK_LEFT_EVENT 0x0F +#define STMFTS_MASK_X_MSB 0x0F +#define STMFTS_MASK_Y_LSB 0xF0 + +/* key related event masks */ +#define STMFTS_MASK_KEY_NO_TOUCH 0x00 +#define STMFTS_MASK_KEY_MENU 0x01 +#define STMFTS_MASK_KEY_BACK 0x02 + +#define STMFTS_EVENT_SIZE 8 +#define STMFTS_STACK_DEPTH 32 +#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH) +#define STMFTS_MAX_FINGERS 10 + +typedef enum _touch_ito_error { + ITO_NO_ERROR = 0, + ITO_FORCE_OPEN, + ITO_SENSE_OPEN, + ITO_FORCE_SHRT_GND, + ITO_SENSE_SHRT_GND, + ITO_FORCE_SHRT_VCM, + ITO_SENSE_SHRT_VCM, + ITO_FORCE_SHRT_FORCE, + ITO_SENSE_SHRT_SENSE, + ITO_F2E_SENSE, + ITO_FPC_FORCE_OPEN, + ITO_FPC_SENSE_OPEN, + ITO_KEY_FORCE_OPEN, + ITO_KEY_SENSE_OPEN, + ITO_RESERVED0, + ITO_RESERVED1, + ITO_RESERVED2, + ITO_MAX_ERR_REACHED = 0xFF +} touch_ito_error; + +typedef struct _touch_event { + u8 raw[8]; + u16 type; // Event type. + u16 x; // Horizontal coordinates. + u16 y; // Vertical coordinates. + u32 z; + u8 fingers; + bool touch; +} touch_event; + +typedef struct _touch_info { + u16 chip_id; + u16 fw_ver; + u16 config_id; + u16 config_ver; +} touch_info; + +typedef struct _touch_fw_info_t { + u32 fw_id; + u16 ftb_ver; + u16 fw_rev; +} touch_fw_info_t; + +void touch_poll(touch_event *event); +touch_event touch_poll_wait(); +int touch_get_fw_info(touch_fw_info_t *fw); +touch_info touch_get_info(); +int touch_panel_ito_test(u8 *err); +int touch_execute_autotune(); +int touch_sense_enable(); +int touch_power_on(); +void touch_power_off(); + +#endif /* __TOUCH_H_ */ \ No newline at end of file diff --git a/source/libs/compr/blz.c b/bdk/libs/compr/blz.c similarity index 100% rename from source/libs/compr/blz.c rename to bdk/libs/compr/blz.c diff --git a/source/libs/compr/blz.h b/bdk/libs/compr/blz.h similarity index 97% rename from source/libs/compr/blz.h rename to bdk/libs/compr/blz.h index 4171049..a1cce37 100644 --- a/source/libs/compr/blz.h +++ b/bdk/libs/compr/blz.h @@ -17,7 +17,7 @@ #ifndef _BLZ_H_ #define _BLZ_H_ -#include "../../utils/types.h" +#include typedef struct _blz_footer { diff --git a/source/libs/compr/lz.c b/bdk/libs/compr/lz.c similarity index 100% rename from source/libs/compr/lz.c rename to bdk/libs/compr/lz.c diff --git a/source/libs/compr/lz.h b/bdk/libs/compr/lz.h similarity index 100% rename from source/libs/compr/lz.h rename to bdk/libs/compr/lz.h diff --git a/source/libs/fatfs/diskio.h b/bdk/libs/fatfs/diskio.h similarity index 95% rename from source/libs/fatfs/diskio.h rename to bdk/libs/fatfs/diskio.h index d6ae8f8..977124c 100644 --- a/source/libs/fatfs/diskio.h +++ b/bdk/libs/fatfs/diskio.h @@ -9,7 +9,7 @@ extern "C" { #endif -#include "../../utils/types.h" +#include /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -23,6 +23,13 @@ typedef enum { RES_PARERR /* 4: Invalid Parameter */ } DRESULT; +typedef enum { + DRIVE_SD = 0, + DRIVE_RAM = 1, + DRIVE_EMMC = 2, + DRIVE_BIS = 3 +} DDRIVE; + /*---------------------------------------*/ /* Prototypes for disk control functions */ diff --git a/source/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c similarity index 100% rename from source/libs/fatfs/ff.c rename to bdk/libs/fatfs/ff.c diff --git a/source/libs/fatfs/ff.h b/bdk/libs/fatfs/ff.h similarity index 99% rename from source/libs/fatfs/ff.h rename to bdk/libs/fatfs/ff.h index 6ace114..368ad9d 100644 --- a/source/libs/fatfs/ff.h +++ b/bdk/libs/fatfs/ff.h @@ -26,8 +26,8 @@ extern "C" { #endif -#include "../../utils/types.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ +#include /* Basic integer types */ +#include /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). @@ -246,7 +246,7 @@ typedef enum { FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ -#ifdef FF_FASTFS +#if FF_FASTFS FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */ #else diff --git a/source/libs/fatfs/ffunicode.c b/bdk/libs/fatfs/ffunicode.c similarity index 100% rename from source/libs/fatfs/ffunicode.c rename to bdk/libs/fatfs/ffunicode.c diff --git a/bdk/libs/lv_conf.h b/bdk/libs/lv_conf.h new file mode 100644 index 0000000..ab7f311 --- /dev/null +++ b/bdk/libs/lv_conf.h @@ -0,0 +1,369 @@ +/* + * 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 . + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#include +#include +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +# define LV_MEM_SIZE NYX_LV_MEM_SZ /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +# define LV_MEM_ADR NYX_LV_MEM_ADR /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (1280) +#define LV_VER_RES (720) + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI 100 + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ + +/*Screen refresh period in milliseconds*/ +#define LV_REFR_PERIOD 33 + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#define LV_VDB_SIZE (LV_VER_RES * LV_HOR_RES) + + /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ + + /* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR NYX_LV_VDB_ADR + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#define LV_VDB_DOUBLE 0 + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB2_ADR 0 + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 33 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME 1000 //Fix keyb /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/ +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 0 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ + +/*Feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 0 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW 0 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 0 /*1: Enable file system (might be required for images*/ +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ + +/*Compiler settings*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ + +/*HAL settings*/ +#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#if LV_TICK_CUSTOM == 1 +#define LV_TICK_CUSTOM_INCLUDE /*Header for the sys time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (get_tmr_ms()) /*Expression evaluating to current systime in ms*/ +#endif /*LV_TICK_CUSTOM*/ + + +/*Log settings*/ +#define USE_LV_LOG 0 /*Enable/disable the log module*/ +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ +# define LV_LOG_PRINTF 1 +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ + +#define USE_LV_THEME_HEKATE 1 /*Flat theme with bold colors and light shadows*/ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#define LV_FONT_QUALITY 8 + +#define USE_UBUNTU_MONO LV_FONT_QUALITY + +#define USE_INTERUI_20 LV_FONT_QUALITY +#define USE_INTERUI_30 LV_FONT_QUALITY + +#define USE_HEKATE_SYMBOL_20 USE_INTERUI_20 +#define USE_HEKATE_SYMBOL_30 USE_INTERUI_30 +#define USE_HEKATE_SYMBOL_120 LV_FONT_QUALITY + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#define LV_FONT_CUSTOM_DECLARE + +#define LV_FONT_DEFAULT &interui_30 /*Always set a default font from the built-in fonts*/ + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#define LV_OBJ_REALIGN 1 // 0 in OG gui /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 0 /*Enable indexed (palette) images*/ +# define LV_IMG_CF_ALPHA 0 /*Enable alpha indexed images*/ +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 + +/*Arc (dependencies: -)*/ +#define USE_LV_ARC 0 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +# if USE_LV_TABVIEW != 0 +# define LV_TABVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/*Tileview (dependencies: lv_page) */ +#define USE_LV_TILEVIEW 0 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 0 + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#define USE_LV_GAUGE 0 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 0 + +/*Table (dependencies: lv_label)*/ +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 0 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#define USE_LV_SPINBOX 0 + +/*Calendar (dependencies: -)*/ +#define USE_LV_CALENDAR 0 + +/*Preload (dependencies: lv_arc)*/ +#define USE_LV_PRELOAD 0 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +/*Canvas (dependencies: lv_img)*/ +#define USE_LV_CANVAS 0 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 0 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif + +/*Image Button (dependencies: lv_btn*/ +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 0 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +# define LV_DDLIST_ANIM_TIME 100 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +#endif /*LV_CONF_H*/ + diff --git a/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md b/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c7d7eeb --- /dev/null +++ b/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/bdk/libs/lvgl/docs/CONTRIBUTING.md b/bdk/libs/lvgl/docs/CONTRIBUTING.md new file mode 100644 index 0000000..5d1d912 --- /dev/null +++ b/bdk/libs/lvgl/docs/CONTRIBUTING.md @@ -0,0 +1,103 @@ +# Contributing to Littlev Graphics Library + +**Welcome! It's glad to see that you are interested in contributing to LittlevGL! There are several types of task where you can help to build a better library! Let's see how to get started!** + + +There are many different possibilities to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can: +- answer other's questions +- report and/or fix bugs +- suggest and/or implement new features +- improve and/or translate the documentation +- write a blog post about your experiences + +But first, start with the most Frequently Asked Questions. + +## FAQ about contributing + +### What license does my code need to be under? + +Any code added to LittlevGL must be licensed under [MIT](https://choosealicense.com/licenses/mit/) or another license that is fully compatible. Contributions under other licenses are highly likely to be rejected. + +If you borrow code from another project, please make sure to add their copyright notice to your contribution. + +### Where do I ask questions, give feedback, or report bugs? + +We use the [forum](http://forum.littlevgl.com/) for questions, feature suggestions, and discussions. + +We use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) to report bugs. + +For both of these there are some rules: +- Be kind and friendly. +- Speak about one thing in one issue. +- Give feedback and close the issue if your question is answered. +- Explain exactly what you experience or expect. _"The button is not working"_ is not enough info to get help. +- For most issues you should send an absolute minimal code example in order to reproduce the issue. Ideally this should be easily usable in the PC simulator. +- Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) to format your post. +- If you don't get any answer in a week write a comment like "Can somebody help?". Maybe your issue wasn't noticed. + +### How can I send fixes and improvements? +Merging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide about them: +1. **Fork** the [lvgl repository](https://github.com/littlevgl/lvgl). To do this click the "Fork" button in the top right corner. It will "copy" the `lvgl` repository to your GitHub account (`https://github.com/your_name?tab=repositories`) +2. **Clone** the forked repository and add your updates +3. **Create a PR** on the GitHub on the page of you `lvgl` repository(`https://github.com/your_name/lvgl`) by hitting the "New pull request" button +4. **Set the base branch**. It means where you want to merge your update. Bugfixes for the last release go to `master`, new features to the actual `dev-x.y` branch. +5. **Describe** what is in the update. An example code is welcome if applicable. + +Some advice: +- If you are not sure about your fix or feature it's better to open an issue first, and discuss the details there. +- Maybe your fix or update won't be perfect at first. Don't be afraid, just improve it and push the new commits. The PR will be updated accordingly. +- If your update needs some extra work it's okay to say: _"I'm busy now and I will improve it soon"_ or _"Sorry, I don't have time to improve it, I hope it helps in this form too"_. So it's better to say don't have time to continue then saying nothing. +- Please read and follow this [guide about the coding style](https://docs.littlevgl.com/#Coding-Style-Guide) + + +### Where is the documentation? + +You can read the documentation here: https://docs.littlevgl.com/ +You can edit the documentation here: https://github.com/littlevgl/doc + +### Where is the blog? + +You can read the blog here: https://blog.littlevgl.com/ +You can edit the blog here: https://github.com/littlevgl/blog + + +## So how and where can I contribute? + +### Answering other's questions + +It's a great way to contribute to the library if you already use it. Just go the [issue tracker](https://github.com/littlevgl/lvgl/issues), read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion. + +### Reporting and/or fixing bugs +For simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet. + +### Suggesting and/or implementing new features +If you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started. + +During the implementation don't forget the [Code style guide](https://docs.littlevgl.com/#Coding-Style-Guide). + +### Improving and/or translating the documentation + +The documentation of LittlevGL is written in Markdown and available [here](https://github.com/littlevgl/doc) for editing. If you find some parts of the documentation obscure or insufficient just search the related `.md` file, hit the edit icon and add your updates. This way a new Pull request will be generated automatically. + +If you can devote more time to improve the documentation you can translate it! +1. Just copy the English `.md` files from the root folder to `locale/LANGUAGE_CODE` (language code is e.g. DE, FR, ES etc) +2. Append the language code the end of files (e.g. Welcome_fr.md) +3. Update the filenames in `_Sidebar.md` +4. Translate the page(s) you want +5. Create a Pull request + +### Writing a blog post about your experiences + +Have ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick? +You can share your knowledge on LittelvGL's blog! It's super easy to add your own post: +- Fork and clone the [blog repository](https://github.com/littlevgl/blog) +- Add your post in Markdown to the `_posts` folder. +- Store the images and other resources in a dedicated folder in `assets` +- Create a Pull Request + +The blog uses [Jekyll](https://jekyllrb.com/) to convert the `.md` files to a webpage. You can easily [run Jekyll offline](https://jekyllrb.com/docs/) to check your post before creating the Pull request + +## Summary + +I hope you have taken a liking to contribute to LittelvGL. A helpful and friendly community is waiting for you! :) + diff --git a/bdk/libs/lvgl/docs/astyle_c b/bdk/libs/lvgl/docs/astyle_c new file mode 100644 index 0000000..9b9d7f3 --- /dev/null +++ b/bdk/libs/lvgl/docs/astyle_c @@ -0,0 +1 @@ +--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent= diff --git a/bdk/libs/lvgl/docs/astyle_h b/bdk/libs/lvgl/docs/astyle_h new file mode 100644 index 0000000..d9c7633 --- /dev/null +++ b/bdk/libs/lvgl/docs/astyle_h @@ -0,0 +1 @@ +--convert-tabs --indent=spaces=4 diff --git a/bdk/libs/lvgl/licence.txt b/bdk/libs/lvgl/licence.txt new file mode 100644 index 0000000..beaef1d --- /dev/null +++ b/bdk/libs/lvgl/licence.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bdk/libs/lvgl/lv_core/lv_core.mk b/bdk/libs/lvgl/lv_core/lv_core.mk new file mode 100644 index 0000000..9992e3f --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_core.mk @@ -0,0 +1,12 @@ +CSRCS += lv_group.c +CSRCS += lv_indev.c +CSRCS += lv_obj.c +CSRCS += lv_refr.c +CSRCS += lv_style.c +CSRCS += lv_vdb.c +CSRCS += lv_lang.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core +VPATH += :$(LVGL_DIR)/lvgl/lv_core + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core" diff --git a/bdk/libs/lvgl/lv_core/lv_group.c b/bdk/libs/lvgl/lv_core/lv_group.c new file mode 100644 index 0000000..3fd4120 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_group.c @@ -0,0 +1,554 @@ +/** + * @file lv_group.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_group.h" +#if USE_LV_GROUP != 0 +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void style_mod_def(lv_style_t * style); +static void style_mod_edit_def(lv_style_t * style); +static void lv_group_refocus(lv_group_t *g); +static void obj_to_foreground(lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void) +{ + lv_group_t * group = lv_mem_alloc(sizeof(lv_group_t)); + lv_mem_assert(group); + if(group == NULL) return NULL; + lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *)); + + group->style_mod = style_mod_def; + group->style_mod_edit = style_mod_edit_def; + group->obj_focus = NULL; + group->frozen = 0; + group->focus_cb = NULL; + group->click_focus = 1; + group->editing = 0; + + return group; +} + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group) +{ + /*Defocus the the currently focused object*/ + if(group->obj_focus != NULL) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + /*Remove the objects from the group*/ + lv_obj_t ** obj; + LL_READ(group->obj_ll, obj) { + (*obj)->group_p = NULL; + } + + lv_ll_clear(&(group->obj_ll)); + lv_mem_free(group); +} + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) +{ + if(group == NULL) return; + + /*If the object is already in a group and focused then defocus it*/ + if(obj->group_p) { + if(lv_obj_is_focused(obj)) { + lv_group_refocus(obj->group_p); + + LV_LOG_INFO("group: assign object to an other group"); + } + } + + obj->group_p = group; + lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll); + lv_mem_assert(next); + if(next == NULL) return; + *next = obj; + + /* If the head and the tail is equal then there is only one object in the linked list. + * In this case automatically activate it*/ + if(lv_ll_get_head(&group->obj_ll) == next) { + lv_group_refocus(group); + } +} + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj) +{ + lv_group_t * g = obj->group_p; + if(g == NULL) return; + if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/ + + /*Focus on the next object*/ + if(*g->obj_focus == obj) { + /*If this is the only object in the group then focus to nothing.*/ + if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + } + /*If there more objects in the group then focus to the next/prev object*/ + else { + lv_group_refocus(g); + } + } + + /* If the focuses object is still the same then it was the only object in the group but it will be deleted. + * Set the `obj_focus` to NULL to get back to the initial state of the group with zero objects*/ + if(*g->obj_focus == obj) { + g->obj_focus = NULL; + } + + /*Search the object and remove it from its group */ + lv_obj_t ** i; + LL_READ(g->obj_ll, i) { + if(*i == obj) { + lv_ll_rem(&g->obj_ll, i); + lv_mem_free(i); + obj->group_p = NULL; + break; + } + } +} + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj) +{ + lv_group_t * g = obj->group_p; + if(g == NULL) return; + + if(g->frozen != 0) return; + + /*On defocus edit mode must be leaved*/ + lv_group_set_editing(g, false); + + lv_obj_t ** i; + LL_READ(g->obj_ll, i) { + if(*i == obj) { + if(g->obj_focus == i) return; /*Don't focus the already focused object again*/ + if(g->obj_focus != NULL) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*g->obj_focus); + } + + g->obj_focus = i; + + if(g->obj_focus != NULL) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_FOCUS, NULL); + if(g->focus_cb) g->focus_cb(g); + lv_obj_invalidate(*g->obj_focus); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*g->obj_focus); + } + break; + } + } +} + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group) +{ + if(group->frozen) return; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + lv_obj_t ** obj_next; + if(group->obj_focus == NULL) obj_next = lv_ll_get_head(&group->obj_ll); + else obj_next = lv_ll_get_next(&group->obj_ll, group->obj_focus); + + if(obj_next == NULL) { + if(group->wrap) obj_next = lv_ll_get_head(&group->obj_ll); + else obj_next = lv_ll_get_tail(&group->obj_ll); + } + group->obj_focus = obj_next; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + + if(group->focus_cb) group->focus_cb(group); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*group->obj_focus); + } +} + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group) +{ + if(group->frozen) return; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + lv_obj_t ** obj_next; + if(group->obj_focus == NULL) obj_next = lv_ll_get_tail(&group->obj_ll); + else obj_next = lv_ll_get_prev(&group->obj_ll, group->obj_focus); + + if(obj_next == NULL) { + if(group->wrap) obj_next = lv_ll_get_tail(&group->obj_ll); + else obj_next = lv_ll_get_head(&group->obj_ll); + } + group->obj_focus = obj_next; + + if(group->obj_focus != NULL) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + + if(group->focus_cb) group->focus_cb(group); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*group->obj_focus); + } + +} + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en) +{ + if(en == false) group->frozen = 0; + else group->frozen = 1; +} + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c) +{ + lv_obj_t * act = lv_group_get_focused(group); + if(act == NULL) return LV_RES_OK; + + return act->signal_func(act, LV_SIGNAL_CONTROLL, &c); +} + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func) +{ + group->style_mod = style_mod_func; + if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus); +} + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func) +{ + group->style_mod_edit = style_mod_func; + if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus); +} + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb) +{ + group->focus_cb = focus_cb; +} + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit) +{ + uint8_t en_val = edit ? 1 : 0; + + if(en_val == group->editing) return; /*Do not set the same mode again*/ + + group->editing = en_val; + lv_obj_t * focused = lv_group_get_focused(group); + + if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave edit mode*/ + + lv_obj_invalidate(focused); +} + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en) +{ + group->click_focus = en ? 1 : 0; +} + +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy) { + group->refocus_policy = policy & 0x01; +} + +static void lv_group_refocus(lv_group_t *g) { + /*Refocus must temporarily allow wrapping to work correctly*/ + uint8_t temp_wrap = g->wrap; + g->wrap = 1; + + if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT) + lv_group_focus_next(g); + else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV) + lv_group_focus_prev(g); + /*Restore wrap property*/ + g->wrap = temp_wrap; +} + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_wrap(lv_group_t * group, bool en) +{ + group->wrap = en ? 1 : 0; +} + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style) +{ + lv_style_copy(&group->style_tmp, style); + + if(group->editing) { + if(group->style_mod_edit) group->style_mod_edit(&group->style_tmp); + } else { + if(group->style_mod) group->style_mod(&group->style_tmp); + } + return &group->style_tmp; +} + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group) +{ + if(!group) return NULL; + if(group->obj_focus == NULL) return NULL; + + return *group->obj_focus; +} + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->style_mod ; +} + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->style_mod_edit; +} + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->focus_cb; +} + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group) +{ + if(!group) return false; + return group->editing ? true : false; +} + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group) +{ + if(!group) return false; + return group->click_focus ? true : false; +} + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group) +{ + if(!group) return false; + return group->wrap ? true : false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Default style modifier function + * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN. + */ +static void style_mod_def(lv_style_t * style) +{ +#if LV_COLOR_DEPTH != 1 + + /*Make the style to be a little bit orange*/ + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_ORANGE; + + /*If not empty or has border then emphasis the border*/ + if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20; + + style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_ORANGE, LV_OPA_70); + style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_ORANGE, LV_OPA_70); + style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_ORANGE, LV_OPA_60); + + style->text.color = lv_color_mix(style->text.color, LV_COLOR_ORANGE, LV_OPA_70); +#else + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_BLACK; + style->body.border.width = 2; + +#endif + +} + +/** + * Default style modifier function + * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN. + */ +static void style_mod_edit_def(lv_style_t * style) +{ +#if LV_COLOR_DEPTH != 1 + + /*Make the style to be a little bit orange*/ + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_GREEN; + + /*If not empty or has border then emphasis the border*/ + if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20; + + style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_GREEN, LV_OPA_70); + style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_GREEN, LV_OPA_70); + style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_GREEN, LV_OPA_60); + + style->text.color = lv_color_mix(style->text.color, LV_COLOR_GREEN, LV_OPA_70); +#else + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_BLACK; + style->body.border.width = 3; + +#endif + +} + +static void obj_to_foreground(lv_obj_t * obj) +{ + /*Search for 'top' attribute*/ + lv_obj_t * i = obj; + lv_obj_t * last_top = NULL; + while(i != NULL) { + if(i->top != 0) last_top = i; + i = lv_obj_get_parent(i); + } + + if(last_top != NULL) { + /*Move the last_top object to the foreground*/ + lv_obj_t * par = lv_obj_get_parent(last_top); + /*After list change it will be the new head*/ + lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); + lv_obj_invalidate(last_top); + } +} + +#endif /*USE_LV_GROUP != 0*/ diff --git a/bdk/libs/lvgl/lv_core/lv_group.h b/bdk/libs/lvgl/lv_core/lv_group.h new file mode 100644 index 0000000..6be9b5c --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_group.h @@ -0,0 +1,247 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ +/*For compatibility in signal function define the keys regardless to LV_GROUP*/ +#define LV_GROUP_KEY_UP 17 /*0x11*/ +#define LV_GROUP_KEY_DOWN 18 /*0x12*/ +#define LV_GROUP_KEY_RIGHT 19 /*0x13*/ +#define LV_GROUP_KEY_LEFT 20 /*0x14*/ +#define LV_GROUP_KEY_ESC 27 /*0x1B*/ +#define LV_GROUP_KEY_DEL 127 /*0x7F*/ +#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/ +#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/ +#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/ +#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/ + +#if USE_LV_GROUP != 0 +/********************** + * TYPEDEFS + **********************/ +struct _lv_group_t; + +typedef void (*lv_group_style_mod_func_t)(lv_style_t *); +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); + +typedef struct _lv_group_t +{ + lv_ll_t obj_ll; /*Linked list to store the objects in the group */ + lv_obj_t ** obj_focus; /*The object in focus*/ + lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/ + lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/ + lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ + lv_style_t style_tmp; /*Stores the modified style of the focused object */ + uint8_t frozen :1; /*1: can't focus to new object*/ + uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/ + uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */ + uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/ + uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/ +} lv_group_t; + +typedef enum _lv_group_refocus_policy_t { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void); + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group); + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj); + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group); + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group); + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en); + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c); + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb); + +/** + * Set whether the next or previous item in a group is focused if the currently focussed obj is deleted. + * @param group pointer to a group + * @param new refocus policy enum + */ +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy); + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit); + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en); + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +void lv_group_set_wrap(lv_group_t * group, bool en); + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group); + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group); + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group); + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group); + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group); + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GROUP != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_indev.c b/bdk/libs/lvgl/lv_core/lv_indev.c new file mode 100644 index 0000000..763abf7 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_indev.c @@ -0,0 +1,971 @@ +/** + * @file lv_indev_proc.c + * + */ + +/********************* + * INCLUDES + ********************/ +#include "lv_indev.h" + +#include "../lv_hal/lv_hal_tick.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_refr.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_rbasic.h" +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +#if LV_INDEV_READ_PERIOD != 0 +static void indev_proc_task(void * param); +static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_proc_press(lv_indev_proc_t * proc); +static void indev_proc_release(lv_indev_proc_t * proc); +static void indev_proc_reset_query_handler(lv_indev_t * indev); +static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj); +static void indev_drag(lv_indev_proc_t * state); +static void indev_drag_throw(lv_indev_proc_t * state); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_indev_t * indev_act; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void) +{ +#if LV_INDEV_READ_PERIOD != 0 + lv_task_create(indev_proc_task, LV_INDEV_READ_PERIOD, LV_TASK_PRIO_MID, NULL); +#endif + + lv_indev_reset(NULL); /*Reset all input devices*/ +} + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void) +{ + return indev_act; +} + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev) +{ + if(indev == NULL) return LV_INDEV_TYPE_NONE; + + return indev->driver.type; +} +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev) +{ + if(indev) indev->proc.reset_query = 1; + else { + lv_indev_t * i = lv_indev_next(NULL); + while(i) { + i->proc.reset_query = 1; + i = lv_indev_next(i); + } + } +} + +/** + * Reset the long press state of an input device + * @param indev pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev) +{ + indev->proc.long_pr_sent = 0; + indev->proc.longpr_rep_timestamp = lv_tick_get(); + indev->proc.pr_timestamp = lv_tick_get(); +} + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable) +{ + lv_indev_t * i = lv_indev_next(NULL); + + while(i) { + if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0; + i = lv_indev_next(i); + } +} + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj) +{ + if(indev->driver.type != LV_INDEV_TYPE_POINTER) return; + + indev->cursor = cur_obj; + if (indev->cursor) + { + lv_obj_set_parent(indev->cursor, lv_layer_sys()); + lv_obj_set_pos(indev->cursor, indev->proc.act_point.x, indev->proc.act_point.y); + } +} + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group) +{ + if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) indev->group = group; +} +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points) +{ + if(indev->driver.type == LV_INDEV_TYPE_BUTTON) indev->btn_points = points; +} + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback) +{ + indev->feedback = feedback; +} + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point) +{ + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) { + point->x = -1; + point->y = -1; + } else { + point->x = indev->proc.act_point.x; + point->y = indev->proc.act_point.y; + } +} + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev) +{ + if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0; + else return indev->proc.last_key; +} + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev) +{ + if(indev == NULL) return false; + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false; + return indev->proc.drag_in_prog == 0 ? false : true; +} + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point) +{ + if(indev == NULL) { + point->x = 0; + point->y = 0; + return; + } + + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) { + point->x = 0; + point->y = 0; + } else { + point->x = indev->proc.vect.x; + point->y = indev->proc.vect.y; + } +} + +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev) +{ + uint32_t t; + + if(indev) return t = lv_tick_elaps(indev->last_activity_time); + + lv_indev_t * i; + t = UINT16_MAX; + i = lv_indev_next(NULL); + while(i) { + t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time)); + i = lv_indev_next(i); + } + + return t; +} + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev) +{ + return indev->feedback; +} + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev) +{ + indev->proc.wait_unil_release = 1; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_INDEV_READ_PERIOD != 0 +/** + * Called periodically to handle the input devices + * @param param unused + */ +static void indev_proc_task(void * param) +{ + (void)param; + + + LV_LOG_TRACE("indev task started"); + + lv_indev_data_t data; + lv_indev_t * i; + i = lv_indev_next(NULL); + + /*Read and process all indevs*/ + while(i) { + indev_act = i; + + /*Handle reset query before processing the point*/ + indev_proc_reset_query_handler(i); + + if(i->proc.disabled == 0) { + bool more_to_read; + do { + /*Read the data*/ + more_to_read = lv_indev_read(i, &data); + indev_proc_reset_query_handler(i); /*The active object might deleted even in the read function*/ + i->proc.state = data.state; + + if(i->proc.state == LV_INDEV_STATE_PR) { + i->last_activity_time = lv_tick_get(); + } + + if(i->driver.type == LV_INDEV_TYPE_POINTER) { + indev_pointer_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) { + indev_keypad_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_ENCODER) { + indev_encoder_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_BUTTON) { + indev_button_proc(i, &data); + } + /*Handle reset query if it happened in during processing*/ + indev_proc_reset_query_handler(i); + } while(more_to_read); + } + i = lv_indev_next(i); /*Go to the next indev*/ + } + + indev_act = NULL; /*End of indev processing, so no act indev*/ + + LV_LOG_TRACE("indev task finished"); +} + + +/** + * Process a new point from LV_INDEV_TYPE_POINTER input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data) +{ + /*Move the cursor if set and moved*/ + if(i->cursor != NULL && + (i->proc.last_point.x != data->point.x || + i->proc.last_point.y != data->point.y)) { + /*Use cursor's center as pointer*/ + uint32_t off_x = lv_obj_get_width(i->cursor) >> 1; + uint32_t off_y = lv_obj_get_height(i->cursor) >> 1; + lv_obj_set_pos(i->cursor, data->point.x - off_x, data->point.y - off_y); + } + + i->proc.act_point.x = data->point.x; + i->proc.act_point.y = data->point.y; + + if(i->proc.state == LV_INDEV_STATE_PR) { +#if LV_INDEV_POINT_MARKER != 0 + lv_area_t area; + area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1); + area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1); + area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER); +#endif + indev_proc_press(&i->proc); + } else { + indev_proc_release(&i->proc); + } + + i->proc.last_point.x = i->proc.act_point.x; + i->proc.last_point.y = i->proc.act_point.y; +} + +/** + * Process a new point from LV_INDEV_TYPE_KEYPAD input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data) +{ +#if USE_LV_GROUP + if(i->group == NULL) return; + + /*Key press happened*/ + if(data->state == LV_INDEV_STATE_PR && + i->proc.last_state == LV_INDEV_STATE_REL) { + i->proc.pr_timestamp = lv_tick_get(); + lv_obj_t * focused = lv_group_get_focused(i->group); + if(focused && data->key == LV_GROUP_KEY_ENTER) { + focused->signal_func(focused, LV_SIGNAL_PRESSED, indev_act); + } + } + /*Pressing*/ + else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) { + if(data->key == LV_GROUP_KEY_ENTER && + i->proc.long_pr_sent == 0 && + lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + /*On enter long press leave edit mode.*/ + lv_obj_t * focused = lv_group_get_focused(i->group); + if(focused) { + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + i->proc.long_pr_sent = 1; + } + } + } + /*Release happened*/ + else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) { + /*The user might clear the key when it was released. Always release the pressed key*/ + data->key = i->proc.last_key; + + /* Edit mode is not used by KEYPAD devices. + * So leave edit mode if we are in it before focusing on the next/prev object*/ + if(data->key == LV_GROUP_KEY_NEXT || data->key == LV_GROUP_KEY_PREV) { + lv_group_set_editing(i->group, false); + } + + if(data->key == LV_GROUP_KEY_NEXT) { + lv_group_focus_next(i->group); + } else if(data->key == LV_GROUP_KEY_PREV) { + lv_group_focus_prev(i->group); + } else if(data->key == LV_GROUP_KEY_ENTER) { + if(!i->proc.long_pr_sent) { + lv_group_send_data(i->group, data->key); + } + } else { + lv_group_send_data(i->group, data->key); + } + + if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/ + + i->proc.pr_timestamp = 0; + i->proc.long_pr_sent = 0; + } + + i->proc.last_state = data->state; + i->proc.last_key = data->key; +#else + (void)data; /*Unused*/ + (void)i; /*Unused*/ +#endif +} + +/** + * Process a new point from LV_INDEV_TYPE_ENCODER input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data) +{ +#if USE_LV_GROUP + if(i->group == NULL) return; + + /*Process the steps first. They are valid only with released button*/ + if(data->state == LV_INDEV_STATE_REL) { + /*In edit mode send LEFT/RIGHT keys*/ + if(lv_group_get_editing(i->group)) { + int32_t s; + if(data->enc_diff < 0) { + for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_LEFT); + } else if(data->enc_diff > 0) { + for(s = 0; s < data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_RIGHT); + } + } + /*In navigate mode focus on the next/prev objects*/ + else { + int32_t s; + if(data->enc_diff < 0) { + for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(i->group); + } else if(data->enc_diff > 0) { + for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(i->group); + } + } + } + + /*Key press happened*/ + if(data->state == LV_INDEV_STATE_PR && + i->proc.last_state == LV_INDEV_STATE_REL) { + i->proc.pr_timestamp = lv_tick_get(); + } + /*Pressing*/ + else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) { + if(i->proc.long_pr_sent == 0 && + lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + /*On enter long press leave edit mode.*/ + lv_obj_t * focused = lv_group_get_focused(i->group); + + bool editable = false; + if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable); + + if(editable) { + if(i->group->obj_ll.head != i->group->obj_ll.tail) + lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/ + else if(focused) + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + } + /*If not editable then just send a long press signal*/ + else { + if(focused) + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + } + i->proc.long_pr_sent = 1; + } + } + /*Release happened*/ + else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) { + lv_obj_t * focused = lv_group_get_focused(i->group); + bool editable = false; + if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable); + + /*The button was released on a non-editable object. Just send enter*/ + if(!editable) { + lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); + } + /*An object is being edited and the button is releases. Just send enter */ + else if(i->group->editing) { + if(!i->proc.long_pr_sent || i->group->obj_ll.head == i->group->obj_ll.tail) + lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); /*Ignore long pressed enter release because it comes from mode switch*/ + } + /*If the focused object is editable and now in navigate mode then enter edit mode*/ + else if(editable && !i->group->editing && !i->proc.long_pr_sent) { + lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/ + } + + if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/ + + i->proc.pr_timestamp = 0; + i->proc.long_pr_sent = 0; + } + + i->proc.last_state = data->state; + i->proc.last_key = data->key; +#else + (void)data; /*Unused*/ + (void)i; /*Unused*/ +#endif +} + +/** + * Process new points from a input device. indev->state.pressed has to be set + * @param indev pointer to an input device state + * @param x x coordinate of the next point + * @param y y coordinate of the next point + */ +static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data) +{ + i->proc.act_point.x = i->btn_points[data->btn].x; + i->proc.act_point.y = i->btn_points[data->btn].y; + + /*Still the same point is pressed*/ + if(i->proc.last_point.x == i->proc.act_point.x && + i->proc.last_point.y == i->proc.act_point.y && + data->state == LV_INDEV_STATE_PR) { +#if LV_INDEV_POINT_MARKER != 0 + lv_area_t area; + area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1); + area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1); + area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER); +#endif + indev_proc_press(&i->proc); + } else { + /*If a new point comes always make a release*/ + indev_proc_release(&i->proc); + } + + i->proc.last_point.x = i->proc.act_point.x; + i->proc.last_point.y = i->proc.act_point.y; +} + +/** + * Process the pressed state of LV_INDEV_TYPE_POINER input devices + * @param indev pointer to an input device 'proc' + */ +static void indev_proc_press(lv_indev_proc_t * proc) +{ + lv_obj_t * pr_obj = proc->act_obj; + + if(proc->wait_unil_release != 0) return; + + /*If there is no last object then search*/ + if(proc->act_obj == NULL) { + pr_obj = indev_search_obj(proc, lv_layer_top()); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act()); + } + /*If there is last object but it is not dragged and not protected also search*/ + else if(proc->drag_in_prog == 0 && + lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now act_obj != NULL*/ + pr_obj = indev_search_obj(proc, lv_layer_top()); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act()); + } + /*If a dragable or a protected object was the last then keep it*/ + else { + + } + + /*If a new object was found reset some variables and send a pressed signal*/ + if(pr_obj != proc->act_obj) { + + proc->last_point.x = proc->act_point.x; + proc->last_point.y = proc->act_point.y; + + /*If a new object found the previous was lost, so send a signal*/ + if(proc->act_obj != NULL) { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act); + if(proc->reset_query != 0) return; + } + + proc->act_obj = pr_obj; /*Save the pressed object*/ + proc->last_obj = proc->act_obj; /*Refresh the last_obj*/ + + if(proc->act_obj != NULL) { + /* Save the time when the obj pressed. + * It is necessary to count the long press time.*/ + proc->pr_timestamp = lv_tick_get(); + proc->long_pr_sent = 0; + proc->drag_range_out = 0; + proc->drag_in_prog = 0; + proc->drag_sum.x = 0; + proc->drag_sum.y = 0; + proc->vect.x = 0; + proc->vect.y = 0; + + /*Search for 'top' attribute*/ + lv_obj_t * i = proc->act_obj; + lv_obj_t * last_top = NULL; + while(i != NULL) { + if(i->top != 0) last_top = i; + i = lv_obj_get_parent(i); + } + + if(last_top != NULL) { + /*Move the last_top object to the foreground*/ + lv_obj_t * par = lv_obj_get_parent(last_top); + /*After list change it will be the new head*/ + lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); + lv_obj_invalidate(last_top); + } + + /*Send a signal about the press*/ + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSED, indev_act); + if(proc->reset_query != 0) return; + } + } + + /*Calculate the vector*/ + proc->vect.x = proc->act_point.x - proc->last_point.x; + proc->vect.y = proc->act_point.y - proc->last_point.y; + + /*If there is active object and it can be dragged run the drag*/ + if(proc->act_obj != NULL) { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSING, indev_act); + if(proc->reset_query != 0) return; + + indev_drag(proc); + if(proc->reset_query != 0) return; + + /*If there is no drag then check for long press time*/ + if(proc->drag_in_prog == 0 && proc->long_pr_sent == 0) { + /*Send a signal about the long press if enough time elapsed*/ + if(lv_tick_elaps(proc->pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act); + if(proc->reset_query != 0) return; + + /*Mark the signal sending to do not send it again*/ + proc->long_pr_sent = 1; + + /*Save the long press time stamp for the long press repeat handler*/ + proc->longpr_rep_timestamp = lv_tick_get(); + } + } + /*Send long press repeated signal*/ + if(proc->drag_in_prog == 0 && proc->long_pr_sent == 1) { + /*Send a signal about the long press repeate if enough time elapsed*/ + if(lv_tick_elaps(proc->longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) { + pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act); + if(proc->reset_query != 0) return; + proc->longpr_rep_timestamp = lv_tick_get(); + + } + } + } +} + +/** + * Process the released state of LV_INDEV_TYPE_POINER input devices + * @param proc pointer to an input device 'proc' + */ +static void indev_proc_release(lv_indev_proc_t * proc) +{ + if(proc->wait_unil_release != 0) { + proc->act_obj = NULL; + proc->last_obj = NULL; + proc->pr_timestamp = 0; + proc->longpr_rep_timestamp = 0; + proc->wait_unil_release = 0; + } + + /*Forgot the act obj and send a released signal */ + if(proc->act_obj != NULL) { + /* If the object was protected against press lost then it possible that + * the object is already not pressed but still it is the `act_obj`. + * In this case send the `LV_SIGNAL_RELEASED` if the indev is ON the `act_obj` */ + if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST)) { + /* Search the object on the current current coordinates. + * The start object is the object itself. If not ON it the the result will be NULL*/ + lv_obj_t * obj_on = indev_search_obj(proc, proc->act_obj); + if(obj_on == proc->act_obj) proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act); + else proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act); + + } + /* The simple case: `act_obj` was not protected against press lost. + * If it is already not pressed then was handled in `indev_proc_press`*/ + else { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act); + } + + if(proc->reset_query != 0) return; + + /*Handle click focus*/ +#if USE_LV_GROUP + /*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/ + lv_group_t * act_g = lv_obj_get_group(proc->act_obj); + if(lv_group_get_editing(act_g)) { + lv_group_set_editing(act_g, false); + } + + /*Check, if the parent is in a group focus on it.*/ + if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_CLICK_FOCUS) == false) { /*Respect the click protection*/ + lv_group_t * g = lv_obj_get_group(proc->act_obj); + lv_obj_t * parent = proc->act_obj; + + while(g == NULL) { + parent = lv_obj_get_parent(parent); + if(parent == NULL) break; + if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/ + parent = NULL; + break; + } + g = lv_obj_get_group(parent); + } + + if(g != NULL && parent != NULL) + if(lv_group_get_click_focus(g)) { + lv_group_focus_obj(parent); + } + } +#endif + + if(proc->reset_query != 0) return; + proc->act_obj = NULL; + proc->pr_timestamp = 0; + proc->longpr_rep_timestamp = 0; + } + + /*The reset can be set in the signal function. + * In case of reset query ignore the remaining parts.*/ + if(proc->last_obj != NULL && proc->reset_query == 0) { + indev_drag_throw(proc); + if(proc->reset_query != 0) return; + } +} + +/** + * Process a new point from LV_INDEV_TYPE_BUTTON input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + * Reset input device if a reset query has been sent to it + * @param indev pointer to an input device + */ +static void indev_proc_reset_query_handler(lv_indev_t * indev) +{ + if(indev->proc.reset_query) { + indev->proc.act_obj = NULL; + indev->proc.last_obj = NULL; + indev->proc.drag_range_out = 0; + indev->proc.drag_in_prog = 0; + indev->proc.long_pr_sent = 0; + indev->proc.pr_timestamp = 0; + indev->proc.longpr_rep_timestamp = 0; + indev->proc.drag_sum.x = 0; + indev->proc.drag_sum.y = 0; + indev->proc.reset_query = 0; + } +} +/** + * Search the most top, clickable object on the last point of an input device + * @param proc pointer to the `lv_indev_proc_t` part of the input device + * @param obj pointer to a start object, typically the screen + * @return pointer to the found object or NULL if there was no suitable object + */ +static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj) +{ + lv_obj_t * found_p = NULL; + + /*If the point is on this object*/ + /*Check its children too*/ + if(lv_area_is_point_on(&obj->coords, &proc->act_point)) { + lv_obj_t * i; + + LL_READ(obj->child_ll, i) { + found_p = indev_search_obj(proc, i); + + /*If a child was found then break*/ + if(found_p != NULL) { + break; + } + } + + /*If then the children was not ok, and this obj is clickable + * and it or its parent is not hidden then save this object*/ + if(found_p == NULL && lv_obj_get_click(obj) != false) { + lv_obj_t * hidden_i = obj; + while(hidden_i != NULL) { + if(lv_obj_get_hidden(hidden_i) == true) break; + hidden_i = lv_obj_get_parent(hidden_i); + } + /*No parent found with hidden == true*/ + if(hidden_i == NULL) found_p = obj; + } + + } + + return found_p; +} + +/** + * Handle the dragging of indev_proc_p->act_obj + * @param indev pointer to a input device state + */ +static void indev_drag(lv_indev_proc_t * state) +{ + lv_obj_t * drag_obj = state->act_obj; + + /*If drag parent is active check recursively the drag_parent attribute*/ + while(lv_obj_get_drag_parent(drag_obj) != false && + drag_obj != NULL) { + drag_obj = lv_obj_get_parent(drag_obj); + } + + if(drag_obj == NULL) return; + + if(lv_obj_get_drag(drag_obj) == false) return; + + /*Count the movement by drag*/ + state->drag_sum.x += state->vect.x; + state->drag_sum.y += state->vect.y; + + /*Enough move?*/ + if(state->drag_range_out == 0) { + /*If a move is greater then LV_DRAG_LIMIT then begin the drag*/ + if(LV_MATH_ABS(state->drag_sum.x) >= LV_INDEV_DRAG_LIMIT || + LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT) { + state->drag_range_out = 1; + } + } + + /*If the drag limit is stepped over then handle the dragging*/ + if(state->drag_range_out != 0) { + /*Set new position if the vector is not zero*/ + if(state->vect.x != 0 || + state->vect.y != 0) { + /*Get the coordinates of the object and modify them*/ + lv_coord_t act_x = lv_obj_get_x(drag_obj); + lv_coord_t act_y = lv_obj_get_y(drag_obj); + uint16_t inv_buf_size = lv_refr_get_buf_size(); /*Get the number of currently invalidated areas*/ + + lv_coord_t prev_x = drag_obj->coords.x1; + lv_coord_t prev_y = drag_obj->coords.y1; + lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); + lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); + + lv_obj_set_pos(drag_obj, act_x + state->vect.x, act_y + state->vect.y); + + /*Set the drag in progress flag if the object is really moved*/ + + if(drag_obj->coords.x1 != prev_x || drag_obj->coords.y1 != prev_y) { + if(state->drag_range_out != 0) { /*Send the drag begin signal on first move*/ + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act); + if(state->reset_query != 0) return; + } + state->drag_in_prog = 1; + } + /*If the object didn't moved then clear the invalidated areas*/ + else { + /*In a special case if the object is moved on a page and + * the scrollable has fit == true and the object is dragged of the page then + * while its coordinate is not changing only the parent's size is reduced */ + lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); + lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); + if(act_par_w == prev_par_w && act_par_h == prev_par_h) { + uint16_t new_inv_buf_size = lv_refr_get_buf_size(); + lv_refr_pop_from_buf(new_inv_buf_size - inv_buf_size); + } + } + } + } +} + +/** + * Handle throwing by drag if the drag is ended + * @param indev pointer to an input device state + */ +static void indev_drag_throw(lv_indev_proc_t * state) +{ + if(state->drag_in_prog == 0) return; + + /*Set new position if the vector is not zero*/ + lv_obj_t * drag_obj = state->last_obj; + + /*If drag parent is active check recursively the drag_parent attribute*/ + while(lv_obj_get_drag_parent(drag_obj) != false && + drag_obj != NULL) { + drag_obj = lv_obj_get_parent(drag_obj); + } + + if(drag_obj == NULL) return; + + /*Return if the drag throw is not enabled*/ + if(lv_obj_get_drag_throw(drag_obj) == false) { + state->drag_in_prog = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + return; + } + + /*Reduce the vectors*/ + state->vect.x = state->vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + state->vect.y = state->vect.y * (100 - LV_INDEV_DRAG_THROW) / 100; + + if(state->vect.x != 0 || + state->vect.y != 0) { + /*Get the coordinates and modify them*/ + lv_area_t coords_ori; + lv_obj_get_coords(drag_obj, &coords_ori); + lv_coord_t act_x = lv_obj_get_x(drag_obj) + state->vect.x; + lv_coord_t act_y = lv_obj_get_y(drag_obj) + state->vect.y; + lv_obj_set_pos(drag_obj, act_x, act_y); + + lv_area_t coord_new; + lv_obj_get_coords(drag_obj, &coord_new); + + /*If non of the coordinates are changed then do not continue throwing*/ + if((coords_ori.x1 == coord_new.x1 || state->vect.x == 0) && + (coords_ori.y1 == coord_new.y1 || state->vect.y == 0)) { + state->drag_in_prog = 0; + state->vect.x = 0; + state->vect.y = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + + } + } + /*If the vectors become 0 -> drag_in_prog = 0 and send a drag end signal*/ + else { + state->drag_in_prog = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + } +} +#endif diff --git a/bdk/libs/lvgl/lv_core/lv_indev.h b/bdk/libs/lvgl/lv_core/lv_indev.h new file mode 100644 index 0000000..19b047c --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_indev.h @@ -0,0 +1,157 @@ +/** + * @file lv_indev_proc.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_core/lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void); + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void); + + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev); + +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev); + +/** + * Reset the long press state of an input device + * @param indev_proc pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev); + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable); + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj); + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group); +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points); + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback); + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point); + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev); + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev); + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev); + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_lang.c b/bdk/libs/lvgl/lv_core/lv_lang.c new file mode 100644 index 0000000..c96ed78 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_lang.c @@ -0,0 +1,117 @@ +/** + * @file lv_lang.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_lang.h" +#if USE_LV_MULTI_LANG + +#include "lv_obj.h" +#include "../lv_misc/lv_gc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lang_set_core(lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ +static uint8_t lang_act = 0; +static const void * (*get_txt)(uint16_t); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id) +{ + lang_act = lang_id; + + lv_obj_t * i; + LL_READ(LV_GC_ROOT(_lv_scr_ll), i) { + i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL); + + lang_set_core(i); + } + + lang_set_core(lv_scr_act()); +} + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)) +{ + get_txt = fp; +} + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id) +{ + if(get_txt == NULL) { + LV_LOG_WARN("lv_lang_get_text: text_func is not specified"); + return NULL; /*No text_get function specified */ + } + if(txt_id == LV_LANG_TXT_ID_NONE) { + LV_LOG_WARN("lv_lang_get_text: attempts to get invalid text ID"); + return NULL; /*Invalid txt_id*/ + } + + return get_txt(txt_id); +} + + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void) +{ + return lang_act; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Change the language of the children. (Called recursively) + * @param obj pointer to an object + */ +static void lang_set_core(lv_obj_t * obj) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL); + + lang_set_core(i); + } +} + +#endif /*USE_LV_MULTI_LANG*/ diff --git a/bdk/libs/lvgl/lv_core/lv_lang.h b/bdk/libs/lvgl/lv_core/lv_lang.h new file mode 100644 index 0000000..5d76f64 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_lang.h @@ -0,0 +1,74 @@ +/** + * @file lv_lang.h + * + */ + +#ifndef LV_LANG_H +#define LV_LANG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_MULTI_LANG + +#include + +/********************* + * DEFINES + *********************/ +#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id); + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)); + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id); + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_MULTI_LANG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_obj.c b/bdk/libs/lvgl/lv_core/lv_obj.c new file mode 100644 index 0000000..95c41a8 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_obj.c @@ -0,0 +1,1986 @@ +/** + * @file lv_base_obj.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "lv_indev.h" +#include "lv_refr.h" +#include "lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_draw/lv_draw_rbasic.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_ufs.h" +#include +#include +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ +#define LV_OBJ_DEF_WIDTH (LV_DPI) +#define LV_OBJ_DEF_HEIGHT (2 * LV_DPI / 3) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff); +static void report_style_mod_core(void * style_p, lv_obj_t * obj); +static void refresh_children_style(lv_obj_t * obj); +static void delete_children(lv_obj_t * obj); +static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); +static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ + +static bool _lv_initialized = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void) +{ + /* Do nothing if already initialized */ + if (_lv_initialized) + return; + + LV_GC_ROOT(_lv_def_scr) = NULL; + LV_GC_ROOT(_lv_act_scr) = NULL; + LV_GC_ROOT(_lv_top_layer) = NULL; + LV_GC_ROOT(_lv_sys_layer) = NULL; + LV_GC_ROOT(_lv_disp_list) = NULL; + LV_GC_ROOT(_lv_indev_list) = NULL; + + LV_LOG_TRACE("lv_init started"); + + /*Initialize the lv_misc modules*/ + lv_mem_init(); + lv_task_init(); + +#if USE_LV_FILESYSTEM + lv_fs_init(); + lv_ufs_init(); +#endif + + lv_font_init(); +#if USE_LV_ANIMATION + lv_anim_init(); +#endif + + /*Init. the sstyles*/ + lv_style_init(); + + /*Initialize the screen refresh system*/ + lv_refr_init(); + + /*Create the default screen*/ + lv_ll_init(&LV_GC_ROOT(_lv_scr_ll), sizeof(lv_obj_t)); + LV_GC_ROOT(_lv_def_scr) = lv_obj_create(NULL, NULL); + + LV_GC_ROOT(_lv_act_scr) = LV_GC_ROOT(_lv_def_scr); + + LV_GC_ROOT(_lv_top_layer) = lv_obj_create(NULL, NULL); + lv_obj_set_style(LV_GC_ROOT(_lv_top_layer), &lv_style_transp_fit); + + LV_GC_ROOT(_lv_sys_layer) = lv_obj_create(NULL, NULL); + lv_obj_set_style(LV_GC_ROOT(_lv_sys_layer), &lv_style_transp_fit); + + /*Refresh the screen*/ + lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr)); + +#if LV_INDEV_READ_PERIOD != 0 + /*Init the input device handling*/ + lv_indev_init(); +#endif + + _lv_initialized = true; + LV_LOG_INFO("lv_init ready"); +} + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) +{ + + lv_obj_t * new_obj = NULL; + /*Create a screen if the parent is NULL*/ + if(parent == NULL) { + LV_LOG_TRACE("Screen create started"); + + new_obj = lv_ll_ins_head(&LV_GC_ROOT(_lv_scr_ll)); + lv_mem_assert(new_obj); + if(new_obj == NULL) return NULL; + + new_obj->par = NULL; /*Screens has no a parent*/ + lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); + + /*Set coordinates to full screen size*/ + new_obj->coords.x1 = 0; + new_obj->coords.y1 = 0; + new_obj->coords.x2 = LV_HOR_RES - 1; + new_obj->coords.y2 = LV_VER_RES - 1; + new_obj->ext_size = 0; + + /*Init realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = LV_ALIGN_CENTER; + new_obj->realign.xofs = 0; + new_obj->realign.yofs = 0; + new_obj->realign.base = NULL; + new_obj->realign.auto_realign = 0; +#endif + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + new_obj->style_p = th->bg; + } else { + new_obj->style_p = &lv_style_scr; + } + /*Set virtual functions*/ + lv_obj_set_signal_func(new_obj, lv_obj_signal); + lv_obj_set_design_func(new_obj, lv_obj_design); + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = 0; +#endif + +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = NULL; +#endif + +#if USE_LV_GROUP + new_obj->group_p = NULL; +#endif + /*Set attributes*/ + new_obj->click = 0; + new_obj->drag = 0; + new_obj->drag_throw = 0; + new_obj->drag_parent = 0; + new_obj->hidden = 0; + new_obj->top = 0; + new_obj->opa_scale_en = 0; + new_obj->protect = LV_PROTECT_NONE; + new_obj->opa_scale = LV_OPA_COVER; + + new_obj->ext_attr = NULL; + + LV_LOG_INFO("Screen create ready"); + } + /*parent != NULL create normal obj. on a parent*/ + else { + LV_LOG_TRACE("Object create started"); + + new_obj = lv_ll_ins_head(&(parent)->child_ll); + lv_mem_assert(new_obj); + if(new_obj == NULL) return NULL; + + + new_obj->par = parent; /*Set the parent*/ + lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); + + /*Set coordinates left top corner of parent*/ + new_obj->coords.x1 = parent->coords.x1; + new_obj->coords.y1 = parent->coords.y1; + new_obj->coords.x2 = parent->coords.x1 + + LV_OBJ_DEF_WIDTH; + new_obj->coords.y2 = parent->coords.y1 + + LV_OBJ_DEF_HEIGHT; + new_obj->ext_size = 0; + + /*Init realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = LV_ALIGN_CENTER; + new_obj->realign.xofs = 0; + new_obj->realign.yofs = 0; + new_obj->realign.base = NULL; + new_obj->realign.auto_realign = 0; +#endif + /*Set appearance*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + new_obj->style_p = th->panel; + } else { + new_obj->style_p = &lv_style_plain_color; + } + + /*Set virtual functions*/ + lv_obj_set_signal_func(new_obj, lv_obj_signal); + lv_obj_set_design_func(new_obj, lv_obj_design); + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = 0; +#endif +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = NULL; +#endif +#if USE_LV_GROUP + new_obj->group_p = NULL; +#endif + + /*Set attributes*/ + new_obj->click = 1; + new_obj->drag = 0; + new_obj->drag_throw = 0; + new_obj->drag_parent = 0; + new_obj->hidden = 0; + new_obj->top = 0; + new_obj->protect = LV_PROTECT_NONE; + new_obj->opa_scale = LV_OPA_COVER; + new_obj->opa_scale_en = 0; + + new_obj->ext_attr = NULL; + } + + if(copy != NULL) { + lv_area_copy(&new_obj->coords, ©->coords); + new_obj->ext_size = copy->ext_size; + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = copy->free_num; +#endif +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = copy->free_ptr; +#endif + + /*Copy realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = copy->realign.align; + new_obj->realign.xofs = copy->realign.xofs; + new_obj->realign.yofs = copy->realign.yofs; + new_obj->realign.base = copy->realign.base; + new_obj->realign.auto_realign = copy->realign.auto_realign; +#endif + + /*Set attributes*/ + new_obj->click = copy->click; + new_obj->drag = copy->drag; + new_obj->drag_throw = copy->drag_throw; + new_obj->drag_parent = copy->drag_parent; + new_obj->hidden = copy->hidden; + new_obj->top = copy->top; + + new_obj->opa_scale_en = copy->opa_scale_en; + new_obj->protect = copy->protect; + new_obj->opa_scale = copy->opa_scale; + + new_obj->style_p = copy->style_p; + +#if USE_LV_GROUP + /*Add to the same group*/ + if(copy->group_p != NULL) { + lv_group_add_obj(copy->group_p, new_obj); + } +#endif + + /*Set the same coordinates for non screen objects*/ + if(lv_obj_get_parent(copy) != NULL && parent != NULL) { + lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy)); + } else { + lv_obj_set_pos(new_obj, 0, 0); + } + + LV_LOG_INFO("Object create ready"); + } + + + /*Send a signal to the parent to notify it about the new child*/ + if(parent != NULL) { + parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, new_obj); + + /*Invalidate the area if not screen created*/ + lv_obj_invalidate(new_obj); + } + + return new_obj; +} + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj) +{ + lv_obj_invalidate(obj); + + /*Delete from the group*/ +#if USE_LV_GROUP + if(obj->group_p != NULL) lv_group_remove_obj(obj); +#endif + + /*Remove the animations from this object*/ +#if USE_LV_ANIMATION + lv_anim_del(obj, NULL); +#endif + + /*Recursively delete the children*/ + lv_obj_t * i; + lv_obj_t * i_next; + i = lv_ll_get_head(&(obj->child_ll)); + while(i != NULL) { + /*Get the next object before delete this*/ + i_next = lv_ll_get_next(&(obj->child_ll), i); + + /*Call the recursive del to the child too*/ + delete_children(i); + + /*Set i to the next node*/ + i = i_next; + } + + /*Remove the object from parent's children list*/ + lv_obj_t * par = lv_obj_get_parent(obj); + if(par == NULL) { /*It is a screen*/ + lv_ll_rem(&LV_GC_ROOT(_lv_scr_ll), obj); + } else { + lv_ll_rem(&(par->child_ll), obj); + } + + /* Reset all input devices if + * the currently pressed object is deleted*/ + lv_indev_t * indev = lv_indev_next(NULL); + while(indev) { + if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) { + lv_indev_reset(indev); + } + indev = lv_indev_next(indev); + } + + /* All children deleted. + * Now clean up the object specific data*/ + obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL); + + /*Delete the base objects*/ + if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr); + lv_mem_free(obj); /*Free the object itself*/ + + /*Send a signal to the parent to notify it about the child delete*/ + if(par != NULL) { + par->signal_func(par, LV_SIGNAL_CHILD_CHG, NULL); + } + + return LV_RES_INV; +} + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t * obj) +{ + lv_obj_t * child = lv_obj_get_child(obj, NULL); + lv_obj_t * child_next; + while(child) { + /* Read the next child before deleting the current + * because the next couldn't be read from a deleted (invalid) node*/ + child_next = lv_obj_get_child(obj, child); + lv_obj_del(child); + child = child_next; + } +} + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj) +{ + if(lv_obj_get_hidden(obj)) return; + + /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/ + lv_obj_t * obj_scr = lv_obj_get_screen(obj); + if(obj_scr == lv_scr_act() || + obj_scr == lv_layer_top() || + obj_scr == lv_layer_sys()) { + /*Truncate recursively to the parents*/ + lv_area_t area_trunc; + lv_obj_t * par = lv_obj_get_parent(obj); + bool union_ok = true; + /*Start with the original coordinates*/ + lv_coord_t ext_size = obj->ext_size; + lv_area_copy(&area_trunc, &obj->coords); + area_trunc.x1 -= ext_size; + area_trunc.y1 -= ext_size; + area_trunc.x2 += ext_size; + area_trunc.y2 += ext_size; + + /*Check through all parents*/ + while(par != NULL) { + union_ok = lv_area_intersect(&area_trunc, &area_trunc, &par->coords); + if(union_ok == false) break; /*If no common parts with parent break;*/ + if(lv_obj_get_hidden(par)) return; /*If the parent is hidden then the child is hidden and won't be drawn*/ + + par = lv_obj_get_parent(par); + } + + if(union_ok != false) lv_inv_area(&area_trunc); + } +} + + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr) +{ + LV_GC_ROOT(_lv_act_scr) = scr; + + lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr)); +} + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) +{ + if(obj->par == NULL) { + LV_LOG_WARN("Can't set the parent of a screen"); + return; + } + + if(parent == NULL) { + LV_LOG_WARN("Can't set parent == NULL to an object"); + return; + } + + + lv_obj_invalidate(obj); + + lv_point_t old_pos; + old_pos.x = lv_obj_get_x(obj); + old_pos.y = lv_obj_get_y(obj); + + lv_obj_t * old_par = obj->par; + + lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj); + obj->par = parent; + lv_obj_set_pos(obj, old_pos.x, old_pos.y); + + /*Notify the original parent because one of its children is lost*/ + old_par->signal_func(old_par, LV_SIGNAL_CHILD_CHG, NULL); + + /*Notify the new parent about the child*/ + parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, obj); + + lv_obj_invalidate(obj); +} + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) +{ + /*Convert x and y to absolute coordinates*/ + lv_obj_t * par = obj->par; + x = x + par->coords.x1; + y = y + par->coords.y1; + + /*Calculate and set the movement*/ + lv_point_t diff; + diff.x = x - obj->coords.x1; + diff.y = y - obj->coords.y1; + + /* Do nothing if the position is not changed */ + /* It is very important else recursive positioning can + * occur without position change*/ + if(diff.x == 0 && diff.y == 0) return; + + /*Invalidate the original area*/ + lv_obj_invalidate(obj); + + /*Save the original coordinates*/ + lv_area_t ori; + lv_obj_get_coords(obj, &ori); + + obj->coords.x1 += diff.x; + obj->coords.y1 += diff.y; + obj->coords.x2 += diff.x; + obj->coords.y2 += diff.y; + + refresh_children_position(obj, diff.x, diff.y); + + /*Inform the object about its new coordinates*/ + obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori); + + /*Send a signal to the parent too*/ + par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + + /*Invalidate the new area*/ + lv_obj_invalidate(obj); +} + + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x) +{ + lv_obj_set_pos(obj, x, lv_obj_get_y(obj)); +} + + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y) +{ + lv_obj_set_pos(obj, lv_obj_get_x(obj), y); +} + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) +{ + + /* Do nothing if the size is not changed */ + /* It is very important else recursive resizing can + * occur without size change*/ + if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) { + return; + } + + /*Invalidate the original area*/ + lv_obj_invalidate(obj); + + /*Save the original coordinates*/ + lv_area_t ori; + lv_obj_get_coords(obj, &ori); + + //Set the length and height + obj->coords.x2 = obj->coords.x1 + w - 1; + obj->coords.y2 = obj->coords.y1 + h - 1; + + + /*Send a signal to the object with its new coordinates*/ + obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori); + + /*Send a signal to the parent too*/ + lv_obj_t * par = lv_obj_get_parent(obj); + if(par != NULL) par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + + /*Invalidate the new area*/ + lv_obj_invalidate(obj); + + /*Automatically realign the object if required*/ +#if LV_OBJ_REALIGN + if(obj->realign.auto_realign) lv_obj_realign(obj); +#endif +} + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w) +{ + lv_obj_set_size(obj, w, lv_obj_get_height(obj)); +} + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h) +{ + lv_obj_set_size(obj, lv_obj_get_width(obj), h); +} + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod) +{ + lv_coord_t new_x = lv_obj_get_x(obj); + lv_coord_t new_y = lv_obj_get_y(obj); + + if(base == NULL) { + base = lv_obj_get_parent(obj); + } + + switch(align) { + case LV_ALIGN_CENTER: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_IN_TOP_LEFT: + new_x = 0; + new_y = 0; + break; + case LV_ALIGN_IN_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = 0; + break; + + case LV_ALIGN_IN_TOP_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = 0; + break; + + case LV_ALIGN_IN_BOTTOM_LEFT: + new_x = 0; + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + case LV_ALIGN_IN_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_IN_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_IN_LEFT_MID: + new_x = 0; + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_IN_RIGHT_MID: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_TOP_LEFT: + new_x = 0; + new_y = -lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_TOP_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_BOTTOM_LEFT: + new_x = 0; + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_LEFT_TOP: + new_x = - lv_obj_get_width(obj); + new_y = 0; + break; + + case LV_ALIGN_OUT_LEFT_MID: + new_x = - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_LEFT_BOTTOM: + new_x = - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_RIGHT_TOP: + new_x = lv_obj_get_width(base); + new_y = 0; + break; + + case LV_ALIGN_OUT_RIGHT_MID: + new_x = lv_obj_get_width(base); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_RIGHT_BOTTOM: + new_x = lv_obj_get_width(base); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + } + + /*Bring together the coordination system of base and obj*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_coord_t base_abs_x = base->coords.x1; + lv_coord_t base_abs_y = base->coords.y1; + lv_coord_t par_abs_x = par->coords.x1; + lv_coord_t par_abs_y = par->coords.y1; + new_x += x_mod + base_abs_x; + new_y += y_mod + base_abs_y; + new_x -= par_abs_x; + new_y -= par_abs_y; + + lv_obj_set_pos(obj, new_x, new_y); + +#if LV_OBJ_REALIGN + /*Save the last align parameters to use them in `lv_obj_realign`*/ + obj->realign.align = align; + obj->realign.xofs = x_mod; + obj->realign.yofs = y_mod; + obj->realign.base = base; + obj->realign.origo_align = 0; +#endif +} + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod) +{ + lv_coord_t new_x = lv_obj_get_x(obj); + lv_coord_t new_y = lv_obj_get_y(obj); + + lv_coord_t obj_w_half = lv_obj_get_width(obj) / 2; + lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2; + + if(base == NULL) { + base = lv_obj_get_parent(obj); + } + + switch(align) { + case LV_ALIGN_CENTER: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_IN_TOP_LEFT: + new_x = -obj_w_half; + new_y = -obj_h_half; + break; + case LV_ALIGN_IN_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_IN_TOP_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_IN_BOTTOM_LEFT: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + case LV_ALIGN_IN_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_IN_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_IN_LEFT_MID: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_IN_RIGHT_MID: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_LEFT: + new_x = -obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_LEFT: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_TOP: + new_x = - obj_w_half ; + new_y = - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_MID: + new_x = - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_BOTTOM: + new_x = - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_TOP: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_MID: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_BOTTOM: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + } + + /*Bring together the coordination system of base and obj*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_coord_t base_abs_x = base->coords.x1; + lv_coord_t base_abs_y = base->coords.y1; + lv_coord_t par_abs_x = par->coords.x1; + lv_coord_t par_abs_y = par->coords.y1; + new_x += x_mod + base_abs_x; + new_y += y_mod + base_abs_y; + new_x -= par_abs_x; + new_y -= par_abs_y; + + lv_obj_set_pos(obj, new_x, new_y); + +#if LV_OBJ_REALIGN + /*Save the last align parameters to use them in `lv_obj_realign`*/ + obj->realign.align = align; + obj->realign.xofs = x_mod; + obj->realign.yofs = y_mod; + obj->realign.base = base; + obj->realign.origo_align = 1; +#endif +} + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj) +{ +#if LV_OBJ_REALIGN + if(obj->realign.origo_align) lv_obj_align_origo(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); + else lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); +#else + (void) obj; + LV_LOG_WARN("lv_obj_realaign: no effect because LV_OBJ_REALIGN = 0"); +#endif +} + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en) +{ +#if LV_OBJ_REALIGN + obj->realign.auto_realign = en ? 1 : 0; +#else + (void) obj; + (void) en; + LV_LOG_WARN("lv_obj_set_auto_realign: no effect because LV_OBJ_REALIGN = 0"); +#endif +} + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style) +{ + obj->style_p = style; + + /*Send a signal about style change to every children with NULL style*/ + refresh_children_style(obj); + + /*Notify the object about the style change too*/ + lv_obj_refresh_style(obj); +} + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj) +{ + lv_obj_invalidate(obj); + obj->signal_func(obj, LV_SIGNAL_STYLE_CHG, NULL); + lv_obj_invalidate(obj); + +} + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style) +{ + lv_obj_t * i; + LL_READ(LV_GC_ROOT(_lv_scr_ll), i) { + if(i->style_p == style || style == NULL) { + lv_obj_refresh_style(i); + } + + report_style_mod_core(style, i); + } +} + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en) +{ + if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ + + obj->hidden = en == false ? 0 : 1; + + if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ + + lv_obj_t * par = lv_obj_get_parent(obj); + par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + +} + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en) +{ + obj->click = (en == true ? 1 : 0); +} + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en) +{ + obj->top = (en == true ? 1 : 0); +} + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en) +{ + if(en == true) lv_obj_set_click(obj, true); /*Drag is useless without enabled clicking*/ + obj->drag = (en == true ? 1 : 0); +} + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en) +{ + obj->drag_throw = (en == true ? 1 : 0); +} + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en) +{ + obj->drag_parent = (en == true ? 1 : 0); +} + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en) +{ + obj->opa_scale_en = en ? 1 : 0; +} + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale) +{ + obj->opa_scale = opa_scale; + lv_obj_invalidate(obj); +} + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot) +{ + obj->protect |= prot; +} + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot) +{ + prot = (~prot) & 0xFF; + obj->protect &= prot; +} + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp) +{ + obj->signal_func = fp; +} + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp) +{ + obj->design_func = fp; +} + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return Normal pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size) +{ + obj->ext_attr = lv_mem_realloc(obj->ext_attr, ext_size); + + return (void *)obj->ext_attr; +} + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj) +{ + obj->ext_size = 0; + obj->signal_func(obj, LV_SIGNAL_REFR_EXT_SIZE, NULL); + + lv_obj_invalidate(obj); +} + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num) +{ + obj->free_num = free_num; +} +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p) +{ + obj->free_ptr = free_p; +} +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb)(lv_obj_t *)) +{ + lv_obj_t * par = lv_obj_get_parent(obj); + + /*Get the direction*/ + bool out = (type & LV_ANIM_DIR_MASK) == LV_ANIM_IN ? false : true; + type = type & (~LV_ANIM_DIR_MASK); + + lv_anim_t a; + a.var = obj; + a.time = time; + a.act_time = (int32_t) - delay; + a.end_cb = (void(*)(void *))cb; + a.path = lv_anim_path_linear; + a.playback_pause = 0; + a.repeat_pause = 0; + a.playback = 0; + a.repeat = 0; + + /*Init to ANIM_IN*/ + switch(type) { + case LV_ANIM_FLOAT_LEFT: + a.fp = (void(*)(void *, int32_t))lv_obj_set_x; + a.start = -lv_obj_get_width(obj); + a.end = lv_obj_get_x(obj); + break; + case LV_ANIM_FLOAT_RIGHT: + a.fp = (void(*)(void *, int32_t))lv_obj_set_x; + a.start = lv_obj_get_width(par); + a.end = lv_obj_get_x(obj); + break; + case LV_ANIM_FLOAT_TOP: + a.fp = (void(*)(void *, int32_t))lv_obj_set_y; + a.start = -lv_obj_get_height(obj); + a.end = lv_obj_get_y(obj); + break; + case LV_ANIM_FLOAT_BOTTOM: + a.fp = (void(*)(void *, int32_t))lv_obj_set_y; + a.start = lv_obj_get_height(par); + a.end = lv_obj_get_y(obj); + break; + case LV_ANIM_GROW_H: + a.fp = (void(*)(void *, int32_t))lv_obj_set_width; + a.start = 0; + a.end = lv_obj_get_width(obj); + break; + case LV_ANIM_GROW_V: + a.fp = (void(*)(void *, int32_t))lv_obj_set_height; + a.start = 0; + a.end = lv_obj_get_height(obj); + break; + case LV_ANIM_NONE: + a.fp = NULL; + a.start = 0; + a.end = 0; + break; + default: + break; + } + + /*Swap start and end in case of ANIM OUT*/ + if(out != false) { + int32_t tmp = a.start; + a.start = a.end; + a.end = tmp; + } + + lv_anim_create(&a); +} + +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void) +{ + return LV_GC_ROOT(_lv_act_scr); +} + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void) +{ + return LV_GC_ROOT(_lv_top_layer); +} + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void) +{ + return LV_GC_ROOT(_lv_sys_layer); +} + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj) +{ + const lv_obj_t * par = obj; + const lv_obj_t * act_p; + + do { + act_p = par; + par = lv_obj_get_parent(act_p); + } while(par != NULL); + + return (lv_obj_t *)act_p; +} + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj) +{ + return obj->par; +} + +/** + * Iterate through the children of an object (start from the "youngest") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child) +{ + lv_obj_t * result = NULL; + + if(child == NULL) { + result = lv_ll_get_head(&obj->child_ll); + } else { + result = lv_ll_get_next(&obj->child_ll, child); + } + + return result; +} + +/** + * Iterate through the children of an object (start from the "oldest") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child) +{ + lv_obj_t * result = NULL; + + if(child == NULL) { + result = lv_ll_get_tail(&obj->child_ll); + } else { + result = lv_ll_get_prev(&obj->child_ll, child); + } + + return result; +} + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj) +{ + lv_obj_t * i; + uint16_t cnt = 0; + + LL_READ(obj->child_ll, i) cnt++; + + return cnt; +} + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p) +{ + lv_area_copy(cords_p, &obj->coords); +} + + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj) +{ + lv_coord_t rel_x; + lv_obj_t * parent = lv_obj_get_parent(obj); + rel_x = obj->coords.x1 - parent->coords.x1; + + return rel_x; +} + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj) +{ + lv_coord_t rel_y; + lv_obj_t * parent = lv_obj_get_parent(obj); + rel_y = obj->coords.y1 - parent->coords.y1; + + return rel_y; +} + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj) +{ + return lv_area_get_width(&obj->coords); +} + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj) +{ + return lv_area_get_height(&obj->coords); +} + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj) +{ + return obj->ext_size; +} + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj) +{ +#if LV_OBJ_REALIGN + return obj->realign.auto_realign ? true : false; +#else + (void) obj; + return false; +#endif +} + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj) +{ + lv_style_t * style_act = obj->style_p; + if(style_act == NULL) { + lv_obj_t * par = obj->par; + + while(par) { + if(par->style_p) { + if(par->style_p->glass == 0) { +#if USE_LV_GROUP == 0 + style_act = par->style_p; +#else + /*Is a parent is focused then use then focused style*/ + lv_group_t * g = lv_obj_get_group(par); + if(lv_group_get_focused(g) == par) { + style_act = lv_group_mod_style(g, par->style_p); + } else { + style_act = par->style_p; + } +#endif + break; + } + } + par = par->par; + } + } +#if USE_LV_GROUP + if(obj->group_p) { + if(lv_group_get_focused(obj->group_p) == obj) { + style_act = lv_group_mod_style(obj->group_p, style_act); + } + } +#endif + + if(style_act == NULL) style_act = &lv_style_plain; + + return style_act; +} + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj) +{ + return obj->hidden == 0 ? false : true; +} + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj) +{ + return obj->click == 0 ? false : true; +} + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feture is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj) +{ + return obj->top == 0 ? false : true; +} + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj) +{ + return obj->drag == 0 ? false : true; +} + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj) +{ + return obj->drag_throw == 0 ? false : true; +} + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj) +{ + return obj->drag_parent == 0 ? false : true; +} + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj) +{ + return obj->opa_scale_en == 0 ? false : true; +} + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj) +{ + const lv_obj_t * parent = obj; + + while(parent) { + if(parent->opa_scale_en) return parent->opa_scale; + parent = lv_obj_get_parent(parent); + } + + return LV_OPA_COVER; +} + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj) +{ + return obj->protect ; +} + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot) +{ + return (obj->protect & prot) == 0 ? false : true ; +} + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj) +{ + return obj->signal_func; +} + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj) +{ + return obj->design_func; +} + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj) +{ + return obj->ext_attr; +} + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf) +{ + lv_obj_type_t tmp; + + memset(buf, 0, sizeof(lv_obj_type_t)); + memset(&tmp, 0, sizeof(lv_obj_type_t)); + + obj->signal_func(obj, LV_SIGNAL_GET_TYPE, &tmp); + + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(tmp.type[cnt] == NULL) break; + } + + + /*Swap the order. The real type comes first*/ + uint8_t i; + for(i = 0; i < cnt; i++) { + buf->type[i] = tmp.type[cnt - 1 - i]; + } +} + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj) +{ + return obj->free_num; +} +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj) +{ + return obj->free_ptr; +} +#endif + + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj) +{ + return obj->group_p; +} + +/** + * Tell whether the ohe object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj) +{ + if(obj->group_p) { + if(lv_group_get_focused(obj->group_p) == obj) return true; + } + + return false; +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the base objects. + * @param obj pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * @param return true/false, depends on 'mode' + */ +static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + + /* Because of the radius it is not sure the area is covered + * Check the areas where there is no radius*/ + lv_style_t * style = lv_obj_get_style(obj); + if(style->body.empty != 0) return false; + + uint16_t r = style->body.radius; + + if(r == LV_RADIUS_CIRCLE) return false; + + lv_area_t area_tmp; + + /*Check horizontally without radius*/ + lv_obj_get_coords(obj, &area_tmp); + area_tmp.x1 += r; + area_tmp.x2 -= r; + if(lv_area_is_in(mask_p, &area_tmp) == false) return false; + + /*Check vertically without radius*/ + lv_obj_get_coords(obj, &area_tmp); + area_tmp.y1 += r; + area_tmp.y2 -= r; + if(lv_area_is_in(mask_p, &area_tmp) == false) return false; + + } else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_style_t * style = lv_obj_get_style(obj); + lv_draw_rect(&obj->coords, mask_p, style, lv_obj_get_opa_scale(obj)); + } + + return true; +} + +/** + * Signal function of the basic object + * @param obj pointer to an object + * @param sign signal type + * @param param parameter for the signal (depends on signal type) + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) +{ + (void)param; + + lv_res_t res = LV_RES_OK; + + lv_style_t * style = lv_obj_get_style(obj); + + lv_indev_t *indev_act = lv_indev_get_act(); + + if(sign > _LV_SIGNAL_FEEDBACK_SECTION_START && sign < _LV_SIGNAL_FEEDBACK_SECTION_END) { + if(indev_act != NULL && indev_act->feedback != NULL) + indev_act->feedback(indev_act, sign); + } + + if(sign == LV_SIGNAL_CHILD_CHG) { + /*Return 'invalid' if the child change signal is not enabled*/ + if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV; + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + if(style->body.shadow.width > obj->ext_size) obj->ext_size = style->body.shadow.width; + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_refresh_ext_size(obj); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + buf->type[0] = "lv_obj"; + } + + return res; +} + +/** + * Reposition the children of an object. (Called recursively) + * @param obj pointer to an object which children will be repositioned + * @param x_diff x coordinate shift + * @param y_diff y coordinate shift + */ +static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + i->coords.x1 += x_diff; + i->coords.y1 += y_diff; + i->coords.x2 += x_diff; + i->coords.y2 += y_diff; + + refresh_children_position(i, x_diff, y_diff); + } +} + +/** + * Refresh the style of all children of an object. (Called recursively) + * @param style_p refresh objects only with this style. + * @param obj pointer to an object + */ +static void report_style_mod_core(void * style_p, lv_obj_t * obj) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + if(i->style_p == style_p || style_p == NULL) { + refresh_children_style(i); + lv_obj_refresh_style(i); + } + + report_style_mod_core(style_p, i); + } +} + +/** + * Recursively refresh the style of the children. Go deeper until a not NULL style is found + * because the NULL styles are inherited from the parent + * @param obj pointer to an object + */ +static void refresh_children_style(lv_obj_t * obj) +{ + lv_obj_t * child = lv_obj_get_child(obj, NULL); + while(child != NULL) { + if(child->style_p == NULL) { + refresh_children_style(child); /*Check children too*/ + lv_obj_refresh_style(child); /*Notify the child about the style change*/ + } else if(child->style_p->glass) { + /*Children with 'glass' parent might be effected if their style == NULL*/ + refresh_children_style(child); + } + child = lv_obj_get_child(obj, child); + } +} + +/** + * Called by 'lv_obj_del' to delete the children objects + * @param obj pointer to an object (all of its children will be deleted) + */ +static void delete_children(lv_obj_t * obj) +{ + lv_obj_t * i; + lv_obj_t * i_next; + i = lv_ll_get_head(&(obj->child_ll)); + + /*Remove from the group; remove before transversing children so that + * the object still has access to all children during the + * LV_SIGNAL_DEFOCUS call*/ +#if USE_LV_GROUP + if(obj->group_p != NULL) lv_group_remove_obj(obj); +#endif + + while(i != NULL) { + /*Get the next object before delete this*/ + i_next = lv_ll_get_next(&(obj->child_ll), i); + + /*Call the recursive del to the child too*/ + delete_children(i); + + /*Set i to the next node*/ + i = i_next; + } + + /*Remove the animations from this object*/ +#if USE_LV_ANIMATION + lv_anim_del(obj, NULL); +#endif + + + /* Reset the input devices if + * the currently pressed object is deleted*/ + lv_indev_t * indev = lv_indev_next(NULL); + while(indev) { + if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) { + lv_indev_reset(indev); + } + indev = lv_indev_next(indev); + } + + /*Remove the object from parent's children list*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_ll_rem(&(par->child_ll), obj); + + /* Clean up the object specific data*/ + obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL); + + /*Delete the base objects*/ + if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr); + lv_mem_free(obj); /*Free the object itself*/ + +} diff --git a/bdk/libs/lvgl/lv_core/lv_obj.h b/bdk/libs/lvgl/lv_core/lv_obj.h new file mode 100644 index 0000000..0ebd916 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_obj.h @@ -0,0 +1,840 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_style.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_ll.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/*Error check of lv_conf.h*/ +#if LV_HOR_RES == 0 || LV_VER_RES == 0 +#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0" +#endif + +#if LV_ANTIALIAS > 1 +#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1" +#endif + +#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0 +#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled" +#endif + +#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES +#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)" +#endif + +#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0 +#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)" +#endif + + +#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/ + +#define LV_MAX_ANCESTOR_NUM 8 + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +enum +{ + LV_DESIGN_DRAW_MAIN, + LV_DESIGN_DRAW_POST, + LV_DESIGN_COVER_CHK, +}; +typedef uint8_t lv_design_mode_t; + +typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); + +enum +{ + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +enum +{ + /*General signals*/ + LV_SIGNAL_CLEANUP, + LV_SIGNAL_CHILD_CHG, + LV_SIGNAL_CORD_CHG, + LV_SIGNAL_STYLE_CHG, + LV_SIGNAL_REFR_EXT_SIZE, + LV_SIGNAL_LANG_CHG, + LV_SIGNAL_GET_TYPE, + + _LV_SIGNAL_FEEDBACK_SECTION_START, + /*Input device related*/ + LV_SIGNAL_PRESSED, + LV_SIGNAL_PRESSING, + LV_SIGNAL_PRESS_LOST, + LV_SIGNAL_RELEASED, + LV_SIGNAL_LONG_PRESS, + LV_SIGNAL_LONG_PRESS_REP, + LV_SIGNAL_DRAG_BEGIN, + LV_SIGNAL_DRAG_END, + + /*Group related*/ + LV_SIGNAL_FOCUS, + LV_SIGNAL_DEFOCUS, + LV_SIGNAL_CONTROLL, + _LV_SIGNAL_FEEDBACK_SECTION_END, + LV_SIGNAL_GET_EDITABLE, +}; +typedef uint8_t lv_signal_t; + +typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param); + +enum +{ + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + +#if LV_OBJ_REALIGN +typedef struct { + const struct _lv_obj_t * base; + lv_coord_t xofs; + lv_coord_t yofs; + lv_align_t align; + uint8_t auto_realign :1; + uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/ +}lv_reailgn_t; +#endif + + +typedef struct _lv_obj_t +{ + struct _lv_obj_t * par; /*Pointer to the parent object*/ + lv_ll_t child_ll; /*Linked list to store the children objects*/ + + lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/ + + lv_signal_func_t signal_func; /*Object type specific signal function*/ + lv_design_func_t design_func; /*Object type specific design function*/ + + void * ext_attr; /*Object type specific extended data*/ + lv_style_t * style_p; /*Pointer to the object's style*/ + +#if LV_OBJ_FREE_PTR != 0 + void * free_ptr; /*Application specific pointer (set it freely)*/ +#endif + +#if USE_LV_GROUP != 0 + void * group_p; /*Pointer to the group of the object*/ +#endif + /*Attributes and states*/ + uint8_t click :1; /*1: Can be pressed by an input device*/ + uint8_t drag :1; /*1: Enable the dragging*/ + uint8_t drag_throw :1; /*1: Enable throwing with drag*/ + uint8_t drag_parent :1; /*1: Parent will be dragged instead*/ + uint8_t hidden :1; /*1: Object is hidden*/ + uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/ + uint8_t opa_scale_en :1; /*1: opa_scale is set*/ + uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/ + lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/ + + lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/ +#if LV_OBJ_REALIGN + lv_reailgn_t realign; +#endif + +#ifdef LV_OBJ_FREE_NUM_TYPE + LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/ +#endif +} lv_obj_t; + +typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj); + +/*Protect some attributes (max. 8 bit)*/ +enum +{ + LV_PROTECT_NONE = 0x00, + LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/ + LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/ + LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/ + LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/ + LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/ + LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/ +}; +typedef uint8_t lv_protect_t; + + +/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/ +typedef struct { + const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */ +} lv_obj_type_t; + +enum +{ + LV_ANIM_NONE = 0, + LV_ANIM_FLOAT_TOP, /*Float from/to the top*/ + LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/ + LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/ + LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/ + LV_ANIM_GROW_H, /*Grow/shrink horizontally*/ + LV_ANIM_GROW_V, /*Grow/shrink vertically*/ +}; +typedef uint8_t lv_anim_builtin_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void); + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy); + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj); + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t *obj); + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr); + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent); + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj); + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en); + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style); + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj); + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style); + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en); + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en); + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en); + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en); + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); + +/** + * Set editable parameter Used by groups and keyboard/encoder control. + * Editable object has something inside to choose (the elements of a list) + * @param obj pointer to an object + * @param en true: enable editing + */ +//void lv_obj_set_editable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale); + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp); + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp); + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size); + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p); +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *)); +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void); + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void); + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj); + +/** + * Iterate through the children of an object (start from the "youngest, lastly created") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Iterate through the children of an object (start from the "oldest", firstly created) + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj); + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p); + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj); + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj); + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj); + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj); + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj); + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj); + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj); + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feature is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj); + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj); + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj); + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj); + + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj); + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj); + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj); + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot); + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj); + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj); + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj); + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj); +#endif + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj); + + +/** + * Tell whether the object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj); + +#endif + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_refr.c b/bdk/libs/lvgl/lv_core/lv_refr.c new file mode 100644 index 0000000..1087304 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_refr.c @@ -0,0 +1,614 @@ +/** + * @file lv_refr.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_refr.h" +#include "lv_vdb.h" +#include "../lv_hal/lv_hal_tick.h" +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_mem.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_INV_FIFO_SIZE +#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */ +#endif + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_area_t area; + uint8_t joined; +} lv_join_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_refr_task(void * param); +static void lv_refr_join_area(void); +static void lv_refr_areas(void); +#if LV_VDB_SIZE == 0 +static void lv_refr_area_no_vdb(const lv_area_t * area_p); +#else +static void lv_refr_area_with_vdb(const lv_area_t * area_p); +static void lv_refr_area_part_vdb(const lv_area_t * area_p); +#endif +static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj); +static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p); +static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_join_t inv_buf[LV_INV_FIFO_SIZE]; +static uint16_t inv_buf_p; +static void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/ +static void (*round_cb)(lv_area_t *); /*If set then called to modify invalidated areas for special display controllers*/ +static uint32_t px_num; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void) +{ + inv_buf_p = 0; + memset(inv_buf, 0, sizeof(inv_buf)); + + lv_task_t * task; + task = lv_task_create(lv_refr_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL); + lv_task_ready(task); /*Be sure the screen will be refreshed immediately on start up*/ +} + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void) +{ + lv_refr_task(NULL); +} + + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p) +{ + /*Clear the invalidate buffer if the parameter is NULL*/ + if(area_p == NULL) { + inv_buf_p = 0; + return; + } + + lv_area_t scr_area; + scr_area.x1 = 0; + scr_area.y1 = 0; + scr_area.x2 = LV_HOR_RES - 1; + scr_area.y2 = LV_VER_RES - 1; + + lv_area_t com_area; + bool suc; + + suc = lv_area_intersect(&com_area, area_p, &scr_area); + + /*The area is truncated to the screen*/ + if(suc != false) { + if(round_cb) round_cb(&com_area); + + /*Save only if this area is not in one of the saved areas*/ + uint16_t i; + for(i = 0; i < inv_buf_p; i++) { + if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return; + } + + /*Save the area*/ + if(inv_buf_p < LV_INV_FIFO_SIZE) { + lv_area_copy(&inv_buf[inv_buf_p].area, &com_area); + } else {/*If no place for the area add the screen*/ + inv_buf_p = 0; + lv_area_copy(&inv_buf[inv_buf_p].area, &scr_area); + } + inv_buf_p ++; + } +} + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + * time_ms: refresh time in [ms] + * px_num: not the drawn pixels but the number of affected pixels of the screen + * (more pixels are drawn because of overlapping objects) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)) +{ + monitor_cb = cb; +} + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t *)) +{ + round_cb = cb; +} + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void) +{ + return inv_buf_p; +} + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num) +{ + if(inv_buf_p < num) inv_buf_p = 0; + else inv_buf_p -= num; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Called periodically to handle the refreshing + * @param param unused + */ +static void lv_refr_task(void * param) +{ + (void)param; + + LV_LOG_TRACE("display refresh task started"); + + uint32_t start = lv_tick_get(); + + if(lv_disp_get_active() == NULL) { + LV_LOG_TRACE("No display is registered"); + return; + } + + lv_refr_join_area(); + + lv_refr_areas(); + + /*If refresh happened ...*/ + if(inv_buf_p != 0) { + + /*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/ +#if LV_VDB_TRUE_DOUBLE_BUFFERED + lv_vdb_t * vdb_p = lv_vdb_get(); + vdb_p->area.x1 = 0; + vdb_p->area.x2 = LV_HOR_RES-1; + vdb_p->area.y1 = 0; + vdb_p->area.y2 = LV_VER_RES - 1; + + /*Flush the content of the VDB*/ + lv_vdb_flush(); + + /* With true double buffering the flushing should be only the address change of the current frame buffer + * Wait until the address change is ready and copy the active content to the other frame buffer (new active VDB) + * The changes will be written to the new VDB.*/ + lv_vdb_t * vdb_act = lv_vdb_get_active(); + lv_vdb_t * vdb_ina = lv_vdb_get_inactive(); + + uint8_t * buf_act = (uint8_t *) vdb_act->buf; + uint8_t * buf_ina = (uint8_t *) vdb_ina->buf; + + uint16_t a; + for(a = 0; a < inv_buf_p; a++) { + if(inv_buf[a].joined == 0) { + lv_coord_t y; + uint32_t start_offs = ((LV_HOR_RES * inv_buf[a].area.y1 + inv_buf[a].area.x1) * LV_VDB_PX_BPP) >> 3; + uint32_t line_length = (lv_area_get_width(&inv_buf[a].area) * LV_VDB_PX_BPP) >> 3; + + for(y = inv_buf[a].area.y1; y <= inv_buf[a].area.y2; y++) { + memcpy(buf_act + start_offs, buf_ina + start_offs, line_length); + start_offs += (LV_HOR_RES * LV_VDB_PX_BPP) >> 3; + } + } + } + +#endif + + /*Clean up*/ + memset(inv_buf, 0, sizeof(inv_buf)); + inv_buf_p = 0; + + /*Call monitor cb if present*/ + if(monitor_cb != NULL) { + monitor_cb(lv_tick_elaps(start), px_num); + } + } + + LV_LOG_TRACE("display refresh task finished"); +} + + +/** + * Join the areas which has got common parts + */ +static void lv_refr_join_area(void) +{ + uint32_t join_from; + uint32_t join_in; + lv_area_t joined_area; + for(join_in = 0; join_in < inv_buf_p; join_in++) { + if(inv_buf[join_in].joined != 0) continue; + + /*Check all areas to join them in 'join_in'*/ + for(join_from = 0; join_from < inv_buf_p; join_from++) { + /*Handle only unjoined areas and ignore itself*/ + if(inv_buf[join_from].joined != 0 || join_in == join_from) { + continue; + } + + /*Check if the areas are on each other*/ + if(lv_area_is_on(&inv_buf[join_in].area, + &inv_buf[join_from].area) == false) { + continue; + } + + lv_area_join(&joined_area, &inv_buf[join_in].area, + &inv_buf[join_from].area); + + /*Join two area only if the joined area size is smaller*/ + if(lv_area_get_size(&joined_area) < + (lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) { + lv_area_copy(&inv_buf[join_in].area, &joined_area); + + /*Mark 'join_form' is joined into 'join_in'*/ + inv_buf[join_from].joined = 1; + } + } + } +} + +/** + * Refresh the joined areas + */ +static void lv_refr_areas(void) +{ + px_num = 0; + uint32_t i; + + for(i = 0; i < inv_buf_p; i++) { + /*Refresh the unjoined areas*/ + if(inv_buf[i].joined == 0) { + /*If there is no VDB do simple drawing*/ +#if LV_VDB_SIZE == 0 + lv_refr_area_no_vdb(&inv_buf[i].area); +#else + /*If VDB is used...*/ + lv_refr_area_with_vdb(&inv_buf[i].area); +#endif + if(monitor_cb != NULL) px_num += lv_area_get_size(&inv_buf[i].area); + } + } + +} + +#if LV_VDB_SIZE == 0 +/** + * Refresh an area if there is no Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_no_vdb(const lv_area_t * area_p) +{ + lv_obj_t * top_p; + + /*Get top object which is not covered by others*/ + top_p = lv_refr_get_top_obj(area_p, lv_scr_act()); + + /*Do the refreshing*/ + lv_refr_obj_and_children(top_p, area_p); + + /*Also refresh top and sys layer unconditionally*/ + lv_refr_obj_and_children(lv_layer_top(), area_p); + lv_refr_obj_and_children(lv_layer_sys(), area_p); +} + +#else + +/** + * Refresh an area if there is Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_with_vdb(const lv_area_t * area_p) +{ + +#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0 + /*Calculate the max row num*/ + lv_coord_t w = lv_area_get_width(area_p); + lv_coord_t h = lv_area_get_height(area_p); + lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2; + + int32_t max_row = (uint32_t) LV_VDB_SIZE / w; + + if(max_row > h) max_row = h; + + + /*Round down the lines of VDB if rounding is added*/ + if(round_cb) { + lv_area_t tmp; + tmp.x1 = 0; + tmp.x2 = 0; + tmp.y1 = 0; + + lv_coord_t y_tmp = max_row - 1; + do { + tmp.y2 = y_tmp; + round_cb(&tmp); + + /*If this height fits into `max_row` then fine*/ + if(lv_area_get_height(&tmp) <= max_row) break; + + /*Decrement the height of the area until it fits into `max_row` after rounding*/ + y_tmp --; + } while(y_tmp != 0); + + if(y_tmp == 0) { + LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to small VDB)"); + return; + } else { + max_row = tmp.y2 + 1; + } + } + + /*Always use the full row*/ + lv_coord_t row; + lv_coord_t row_last = 0; + for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) { + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Calc. the next y coordinates of VDB*/ + vdb_p->area.x1 = area_p->x1; + vdb_p->area.x2 = area_p->x2; + vdb_p->area.y1 = row; + vdb_p->area.y2 = row + max_row - 1; + if(vdb_p->area.y2 > y2) vdb_p->area.y2 = y2; + row_last = vdb_p->area.y2; + lv_refr_area_part_vdb(area_p); + } + + /*If the last y coordinates are not handled yet ...*/ + if(y2 != row_last) { + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Calc. the next y coordinates of VDB*/ + vdb_p->area.x1 = area_p->x1; + vdb_p->area.x2 = area_p->x2; + vdb_p->area.y1 = row; + vdb_p->area.y2 = y2; + + /*Refresh this part too*/ + lv_refr_area_part_vdb(area_p); + } +#else + lv_vdb_t * vdb_p = lv_vdb_get(); + vdb_p->area.x1 = 0; + vdb_p->area.x2 = LV_HOR_RES-1; + vdb_p->area.y1 = 0; + vdb_p->area.y2 = LV_VER_RES - 1; + lv_refr_area_part_vdb(area_p); +#endif +} + +/** + * Refresh a part of an area which is on the actual Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_part_vdb(const lv_area_t * area_p) +{ + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + lv_obj_t * top_p; + + /*Get the new mask from the original area and the act. VDB + It will be a part of 'area_p'*/ + lv_area_t start_mask; + lv_area_intersect(&start_mask, area_p, &vdb_p->area); + + /*Get the most top object which is not covered by others*/ + top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act()); + + /*Do the refreshing from the top object*/ + lv_refr_obj_and_children(top_p, &start_mask); + + /*Also refresh top and sys layer unconditionally*/ + lv_refr_obj_and_children(lv_layer_top(), &start_mask); + lv_refr_obj_and_children(lv_layer_sys(), &start_mask); + + /* In true double buffered mode flush only once when all areas were rendered. + * In normal mode flush after every area */ +#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0 + /*Flush the content of the VDB*/ + lv_vdb_flush(); +#endif +} + +#endif /*LV_VDB_SIZE == 0*/ + +/** + * Search the most top object which fully covers an area + * @param area_p pointer to an area + * @param obj the first object to start the searching (typically a screen) + * @return + */ +static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj) +{ + lv_obj_t * i; + lv_obj_t * found_p = NULL; + + /*If this object is fully cover the draw area check the children too */ + if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) { + LL_READ(obj->child_ll, i) { + found_p = lv_refr_get_top_obj(area_p, i); + + /*If a children is ok then break*/ + if(found_p != NULL) { + break; + } + } + + /*If no better children check this object*/ + if(found_p == NULL) { + lv_style_t * style = lv_obj_get_style(obj); + if(style->body.opa == LV_OPA_COVER && + obj->design_func(obj, area_p, LV_DESIGN_COVER_CHK) != false && + lv_obj_get_opa_scale(obj) == LV_OPA_COVER) { + found_p = obj; + } + } + } + + return found_p; +} + +/** + * Make the refreshing from an object. Draw all its children and the youngers too. + * @param top_p pointer to an objects. Start the drawing from it. + * @param mask_p pointer to an area, the objects will be drawn only here + */ +static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p) +{ + /* Normally always will be a top_obj (at least the screen) + * but in special cases (e.g. if the screen has alpha) it won't. + * In this case use the screen directly */ + if(top_p == NULL) top_p = lv_scr_act(); + + /*Refresh the top object and its children*/ + lv_refr_obj(top_p, mask_p); + + /*Draw the 'younger' sibling objects because they can be on top_obj */ + lv_obj_t * par; + lv_obj_t * i; + lv_obj_t * border_p = top_p; + + par = lv_obj_get_parent(top_p); + + /*Do until not reach the screen*/ + while(par != NULL) { + /*object before border_p has to be redrawn*/ + i = lv_ll_get_prev(&(par->child_ll), border_p); + + while(i != NULL) { + /*Refresh the objects*/ + lv_refr_obj(i, mask_p); + i = lv_ll_get_prev(&(par->child_ll), i); + } + + /*The new border will be there last parents, + *so the 'younger' brothers of parent will be refreshed*/ + border_p = par; + /*Go a level deeper*/ + par = lv_obj_get_parent(par); + } + + /*Call the post draw design function of the parents of the to object*/ + par = lv_obj_get_parent(top_p); + while(par != NULL) { + par->design_func(par, mask_p, LV_DESIGN_DRAW_POST); + par = lv_obj_get_parent(par); + } +} + +/** + * Refresh an object an all of its children. (Called recursively) + * @param obj pointer to an object to refresh + * @param mask_ori_p pointer to an area, the objects will be drawn only here + */ +static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) +{ + /*Do not refresh hidden objects*/ + if(obj->hidden != 0) return; + + bool union_ok; /* Store the return value of area_union */ + /* Truncate the original mask to the coordinates of the parent + * because the parent and its children are visible only here */ + lv_area_t obj_mask; + lv_area_t obj_ext_mask; + lv_area_t obj_area; + lv_coord_t ext_size = obj->ext_size; + lv_obj_get_coords(obj, &obj_area); + obj_area.x1 -= ext_size; + obj_area.y1 -= ext_size; + obj_area.x2 += ext_size; + obj_area.y2 += ext_size; + union_ok = lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area); + + /*Draw the parent and its children only if they ore on 'mask_parent'*/ + if(union_ok != false) { + + /* Redraw the object */ + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN); + //usleep(5 * 1000); /*DEBUG: Wait after every object draw to see the order of drawing*/ + + + /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/ + lv_obj_get_coords(obj, &obj_area); + union_ok = lv_area_intersect(&obj_mask, mask_ori_p, &obj_area); + if(union_ok != false) { + lv_area_t mask_child; /*Mask from obj and its child*/ + lv_obj_t * child_p; + lv_area_t child_area; + LL_READ_BACK(obj->child_ll, child_p) { + lv_obj_get_coords(child_p, &child_area); + ext_size = child_p->ext_size; + child_area.x1 -= ext_size; + child_area.y1 -= ext_size; + child_area.x2 += ext_size; + child_area.y2 += ext_size; + /* Get the union (common parts) of original mask (from obj) + * and its child */ + union_ok = lv_area_intersect(&mask_child, &obj_mask, &child_area); + + /*If the parent and the child has common area then refresh the child */ + if(union_ok) { + /*Refresh the next children*/ + lv_refr_obj(child_p, &mask_child); + } + } + } + + /* If all the children are redrawn make 'post draw' design */ + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST); + + } +} diff --git a/bdk/libs/lvgl/lv_core/lv_refr.h b/bdk/libs/lvgl/lv_core/lv_refr.h new file mode 100644 index 0000000..b93cb10 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_refr.h @@ -0,0 +1,94 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void); + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void); + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p); + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void); + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num); +/********************** + * STATIC FUNCTIONS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_REFR_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_style.c b/bdk/libs/lvgl/lv_core/lv_style.c new file mode 100644 index 0000000..02fbcb2 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_style.c @@ -0,0 +1,357 @@ +/* + * 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 . + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "../lv_misc/lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define STYLE_MIX_MAX 256 +#define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/ + +#define VAL_PROP(v1, v2, r) v1 + (((v2-v1) * r) >> STYLE_MIX_SHIFT) +#define STYLE_ATTR_MIX(attr, r) if(start->attr != end->attr) {res->attr = VAL_PROP(start->attr, end->attr, r);} else {res->attr = start->attr;} + + +/********************** + * TYPEDEFS + **********************/ +#if USE_LV_ANIMATION +typedef struct { + lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it will be modified too*/ + lv_style_t style_end; + lv_style_t * style_anim; + void (*end_cb)(void *); +} lv_style_anim_dsc_t; +#endif + +/********************** + * STATIC PROTOTYPES + **********************/ +#if USE_LV_ANIMATION +static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val); +static void style_animation_common_end_cb(void * ptr); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +lv_style_t lv_style_scr; +lv_style_t lv_style_transp; +lv_style_t lv_style_transp_fit; +lv_style_t lv_style_transp_tight; +lv_style_t lv_style_plain; +lv_style_t lv_style_plain_color; +lv_style_t lv_style_pretty; +lv_style_t lv_style_pretty_color; +lv_style_t lv_style_btn_rel; +lv_style_t lv_style_btn_pr; +lv_style_t lv_style_btn_tgl_rel; +lv_style_t lv_style_btn_tgl_pr; +lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init(void) +{ + /* Not White/Black/Gray colors are created by HSV model with + * HUE = 210*/ + + /*Screen style*/ + lv_style_scr.glass = 0; + lv_style_scr.body.opa = LV_OPA_COVER; + lv_style_scr.body.main_color = LV_COLOR_BLACK; + lv_style_scr.body.grad_color = LV_COLOR_BLACK; + lv_style_scr.body.radius = 0; + lv_style_scr.body.padding.ver = LV_DPI / 12; + lv_style_scr.body.padding.hor = LV_DPI / 12; + lv_style_scr.body.padding.inner = LV_DPI / 12; + + lv_style_scr.body.border.color = LV_COLOR_WHITE; + lv_style_scr.body.border.opa = LV_OPA_COVER; + lv_style_scr.body.border.width = 0; + lv_style_scr.body.border.part = LV_BORDER_FULL; + + lv_style_scr.body.shadow.color = LV_COLOR_GRAY; + lv_style_scr.body.shadow.type = LV_SHADOW_FULL; + lv_style_scr.body.shadow.width = 0; + + lv_style_scr.text.opa = LV_OPA_COVER; + lv_style_scr.text.color = LV_COLOR_HEX(0xFBFBFB); + lv_style_scr.text.font = LV_FONT_DEFAULT; + lv_style_scr.text.letter_space = 3; // Important + lv_style_scr.text.line_space = 2; + + lv_style_scr.image.opa = LV_OPA_COVER; + lv_style_scr.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_scr.image.intense = LV_OPA_TRANSP; + + lv_style_scr.line.opa = LV_OPA_COVER; + lv_style_scr.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_scr.line.width = 2; + lv_style_scr.line.rounded = 0; + + /*Plain style (by default near the same as the screen style)*/ + memcpy(&lv_style_plain, &lv_style_scr, sizeof(lv_style_t)); + + /*Plain color style*/ + memcpy(&lv_style_plain_color, &lv_style_plain, sizeof(lv_style_t)); + lv_style_plain_color.text.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.image.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.line.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.body.main_color = LV_COLOR_MAKE(0x55, 0x96, 0xd8); + lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color; + + /*Pretty style */ + memcpy(&lv_style_pretty, &lv_style_plain, sizeof(lv_style_t)); + lv_style_pretty.text.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.body.main_color = LV_COLOR_WHITE; + lv_style_pretty.body.grad_color = LV_COLOR_SILVER; + lv_style_pretty.body.radius = LV_DPI / 15; + lv_style_pretty.body.border.color = LV_COLOR_MAKE(0x40, 0x40, 0x40); + lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1; + lv_style_pretty.body.border.opa = LV_OPA_30; + + /*Pretty color style*/ + memcpy(&lv_style_pretty_color, &lv_style_pretty, sizeof(lv_style_t)); + lv_style_pretty_color.text.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0); + lv_style_pretty_color.image.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0); + lv_style_pretty_color.line.color = LV_COLOR_MAKE(0xc0, 0xc0, 0xc0); + lv_style_pretty_color.body.main_color = LV_COLOR_MAKE(0x6b, 0x9a, 0xc7); + lv_style_pretty_color.body.grad_color = LV_COLOR_MAKE(0x2b, 0x59, 0x8b); + lv_style_pretty_color.body.border.color = LV_COLOR_MAKE(0x15, 0x2c, 0x42); + + /*Transparent style*/ + memcpy(&lv_style_transp, &lv_style_plain, sizeof(lv_style_t)); + lv_style_transp.body.empty = 1; + lv_style_transp.glass = 1; + lv_style_transp.body.border.width = 0; + + /*Transparent fitting size*/ + memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t)); + lv_style_transp_fit.body.padding.hor = 0; + lv_style_transp_fit.body.padding.ver = 0; + + /*Transparent tight style*/ + memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t)); + lv_style_transp_tight.body.padding.inner = 0; + + /*Button released style*/ + memcpy(&lv_style_btn_rel, &lv_style_plain, sizeof(lv_style_t)); + lv_style_btn_rel.body.main_color = LV_COLOR_MAKE(0x76, 0xa2, 0xd0); + lv_style_btn_rel.body.grad_color = LV_COLOR_MAKE(0x19, 0x3a, 0x5d); + lv_style_btn_rel.body.radius = LV_DPI / 15; + lv_style_btn_rel.body.padding.hor = LV_DPI / 4; + lv_style_btn_rel.body.padding.ver = LV_DPI / 6; + lv_style_btn_rel.body.padding.inner = LV_DPI / 10; + lv_style_btn_rel.body.border.color = LV_COLOR_MAKE(0x0b, 0x19, 0x28); + lv_style_btn_rel.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1; + lv_style_btn_rel.body.border.opa = LV_OPA_70; + lv_style_btn_rel.body.shadow.color = LV_COLOR_GRAY; + lv_style_btn_rel.body.shadow.width = 0; + lv_style_btn_rel.text.color = LV_COLOR_MAKE(0xff, 0xff, 0xff); + lv_style_btn_rel.image.color = LV_COLOR_MAKE(0xff, 0xff, 0xff); + + /*Button pressed style*/ + memcpy(&lv_style_btn_pr, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_pr.body.main_color = LV_COLOR_MAKE(0x33, 0x62, 0x94); + lv_style_btn_pr.body.grad_color = LV_COLOR_MAKE(0x10, 0x26, 0x3c); + lv_style_btn_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + + /*Button toggle released style*/ + memcpy(&lv_style_btn_tgl_rel, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_tgl_rel.body.main_color = LV_COLOR_MAKE(0x0a, 0x11, 0x22); + lv_style_btn_tgl_rel.body.grad_color = LV_COLOR_MAKE(0x37, 0x62, 0x90); + lv_style_btn_tgl_rel.body.border.color = LV_COLOR_MAKE(0x01, 0x07, 0x0d); + lv_style_btn_tgl_rel.text.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + lv_style_btn_tgl_rel.image.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + lv_style_btn_tgl_rel.line.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + + /*Button toggle pressed style*/ + memcpy(&lv_style_btn_tgl_pr, &lv_style_btn_tgl_rel, sizeof(lv_style_t)); + lv_style_btn_tgl_pr.body.main_color = LV_COLOR_MAKE(0x02, 0x14, 0x27); + lv_style_btn_tgl_pr.body.grad_color = LV_COLOR_MAKE(0x2b, 0x4c, 0x70); + lv_style_btn_tgl_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_tgl_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_tgl_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + + /*Button inactive style*/ + memcpy(&lv_style_btn_ina, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_ina.body.main_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8); + lv_style_btn_ina.body.grad_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8); + lv_style_btn_ina.body.border.color = LV_COLOR_MAKE(0x90, 0x90, 0x90); + lv_style_btn_ina.text.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); + lv_style_btn_ina.image.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); + lv_style_btn_ina.line.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); +} + + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src) +{ + memcpy(dest, src, sizeof(lv_style_t)); +} + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio) +{ + STYLE_ATTR_MIX(body.opa, ratio); + STYLE_ATTR_MIX(body.radius, ratio); + STYLE_ATTR_MIX(body.border.width, ratio); + STYLE_ATTR_MIX(body.border.opa, ratio); + STYLE_ATTR_MIX(body.shadow.width, ratio); + STYLE_ATTR_MIX(body.padding.hor, ratio); + STYLE_ATTR_MIX(body.padding.ver, ratio); + STYLE_ATTR_MIX(body.padding.inner, ratio); + STYLE_ATTR_MIX(text.line_space, ratio); + STYLE_ATTR_MIX(text.letter_space, ratio); + STYLE_ATTR_MIX(text.opa, ratio); + STYLE_ATTR_MIX(line.width, ratio); + STYLE_ATTR_MIX(line.opa, ratio); + STYLE_ATTR_MIX(image.intense, ratio); + STYLE_ATTR_MIX(image.opa, ratio); + + lv_opa_t opa = ratio == STYLE_MIX_MAX ? LV_OPA_COVER : ratio; + + res->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa); + res->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa); + res->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa); + res->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa); + res->text.color = lv_color_mix(end->text.color, start->text.color, opa); + res->image.color = lv_color_mix(end->image.color, start->image.color, opa); + res->line.color = lv_color_mix(end->line.color, start->line.color, opa); + + if(ratio < (STYLE_MIX_MAX >> 1)) { + res->body.empty = start->body.empty; + res->body.border.part = start->body.border.part; + res->glass = start->glass; + res->text.font = start->text.font; + res->body.shadow.type = start->body.shadow.type; + res->line.rounded = start->line.rounded; + } else { + res->body.empty = end->body.empty; + res->body.border.part = end->body.border.part; + res->glass = end->glass; + res->text.font = end->text.font; + res->body.shadow.type = end->body.shadow.type; + res->line.rounded = end->line.rounded; + } +} + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim) +{ + lv_style_anim_dsc_t * dsc; + dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t)); + lv_mem_assert(dsc); + if(dsc == NULL) return NULL; + + dsc->style_anim = anim->style_anim; + memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t)); + memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t)); + memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t)); + dsc->end_cb = anim->end_cb; + + + lv_anim_t a; + a.var = (void *)dsc; + a.start = 0; + a.end = STYLE_MIX_MAX; + a.fp = (lv_anim_fp_t)style_animator; + a.path = lv_anim_path_linear; + a.end_cb = style_animation_common_end_cb; + a.act_time = anim->act_time; + a.time = anim->time; + a.playback = anim->playback; + a.playback_pause = anim->playback_pause; + a.repeat = anim->repeat; + a.repeat_pause = anim->repeat_pause; + + lv_anim_create(&a); + + return dsc; +} + +#endif +/********************** + * STATIC FUNCTIONS + **********************/ +#if USE_LV_ANIMATION +/** + * Used by the style animations to set the values of a style according to start and end style. + * @param dsc the 'animated variable' set by lv_style_anim_create() + * @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES + */ +static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val) +{ + const lv_style_t * start = &dsc->style_start; + const lv_style_t * end = &dsc->style_end; + lv_style_t * act = dsc->style_anim; + + lv_style_mix(start, end, act, val); + + lv_obj_report_style_mod(dsc->style_anim); +} + +/** + * Called when a style animation is ready + * It called the user defined call back and free the allocated memories + * @param ptr the 'animated variable' set by lv_style_anim_create() + */ +static void style_animation_common_end_cb(void * ptr) +{ + lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/ + + if(dsc->end_cb) dsc->end_cb(dsc); + + lv_mem_free(dsc); +} + +#endif diff --git a/bdk/libs/lvgl/lv_core/lv_style.h b/bdk/libs/lvgl/lv_core/lv_style.h new file mode 100644 index 0000000..0ba03c8 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_style.h @@ -0,0 +1,198 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/ + +/********************** + * TYPEDEFS + **********************/ + +/*Border types (Use 'OR'ed values)*/ +enum +{ + LV_BORDER_NONE = 0x00, + LV_BORDER_BOTTOM = 0x01, + LV_BORDER_TOP = 0x02, + LV_BORDER_LEFT = 0x04, + LV_BORDER_RIGHT = 0x08, + LV_BORDER_FULL = 0x0F, + LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_part_t; + +/*Shadow types*/ +enum +{ + LV_SHADOW_BOTTOM = 0, + LV_SHADOW_FULL, +}; +typedef uint8_t lv_shadow_type_t; + +typedef struct +{ + uint8_t glass :1; /*1: Do not inherit this style*/ + + struct { + lv_color_t main_color; + lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/ + lv_coord_t radius; + lv_opa_t opa; + + struct { + lv_color_t color; + lv_coord_t width; + lv_border_part_t part; + lv_opa_t opa; + } border; + + struct { + lv_color_t color; + lv_coord_t width; + lv_shadow_type_t type; + } shadow; + + struct { + lv_coord_t ver; + lv_coord_t hor; + lv_coord_t inner; + } padding; + + uint8_t empty :1; /*Transparent background (border still drawn)*/ + } body; + + + struct { + lv_color_t color; + const lv_font_t * font; + lv_coord_t letter_space; + lv_coord_t line_space; + lv_opa_t opa; + } text; + + struct { + lv_color_t color; + lv_opa_t intense; + lv_opa_t opa; + } image; + + struct { + lv_color_t color; + lv_coord_t width; + lv_opa_t opa; + uint8_t rounded :1; /*1: rounded line endings*/ + } line; +} lv_style_t; + +#if USE_LV_ANIMATION +typedef struct { + const lv_style_t * style_start; /*Pointer to the starting style*/ + const lv_style_t * style_end; /*Pointer to the destination style*/ + lv_style_t * style_anim; /*Pointer to a style to animate*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/ + int16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ +} lv_style_anim_t; + +/* Example initialization +lv_style_anim_t a; +a.style_anim = &style_to_anim; +a.style_start = &style_1; +a.style_end = &style_2; +a.act_time = 0; +a.time = 1000; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +a.end_cb = NULL; +lv_style_anim_create(&a); + */ +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init (void); + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src); + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio); + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim); +#endif + +/************************* + * GLOBAL VARIABLES + *************************/ +extern lv_style_t lv_style_scr; +extern lv_style_t lv_style_transp; +extern lv_style_t lv_style_transp_fit; +extern lv_style_t lv_style_transp_tight; +extern lv_style_t lv_style_plain; +extern lv_style_t lv_style_plain_color; +extern lv_style_t lv_style_pretty; +extern lv_style_t lv_style_pretty_color; +extern lv_style_t lv_style_btn_rel; +extern lv_style_t lv_style_btn_pr; +extern lv_style_t lv_style_btn_tgl_rel; +extern lv_style_t lv_style_btn_tgl_pr; +extern lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/bdk/libs/lvgl/lv_core/lv_vdb.c b/bdk/libs/lvgl/lv_core/lv_vdb.c new file mode 100644 index 0000000..38aae34 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_vdb.c @@ -0,0 +1,207 @@ +/** + * @file lv_vdb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_vdb.h" +#if LV_VDB_SIZE != 0 + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_log.h" +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_FLUSH_READY +#define LV_ATTRIBUTE_FLUSH_READY +#endif + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/*Simple VDB*/ +#if LV_VDB_DOUBLE == 0 +# if LV_VDB_ADR == 0 +/*If the buffer address is not specified simply allocate it*/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf[LV_VDB_SIZE_IN_BYTES]; +static lv_vdb_t vdb = {.buf = (lv_color_t *)vdb_buf}; +# else /*LV_VDB_ADR != 0*/ +/*If the buffer address is specified use that address*/ +static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR}; +# endif + +/*LV_VDB_DOUBLE != 0*/ +#else +/*Double VDB*/ +static uint8_t vdb_active = 0; +# if LV_VDB_ADR == 0 +/*If the buffer address is not specified simply allocate it*/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf1[LV_VDB_SIZE_IN_BYTES]; +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf2[LV_VDB_SIZE_IN_BYTES]; +static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}}; +# else /*LV_VDB_ADR != 0*/ +/*If the buffer address is specified use that address*/ +static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}}; +# endif +#endif + +static volatile bool vdb_flushing = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void) +{ +#if LV_VDB_DOUBLE == 0 + /* Wait until VDB is flushing. + * (Until this user calls of 'lv_flush_ready()' in the display drivers's flush function*/ + while(vdb_flushing); + + return &vdb; +#else + /*If already there is an active do nothing*/ + return &vdb[vdb_active]; +#endif +} + +/** + * Flush the content of the VDB + */ +void lv_vdb_flush(void) +{ + lv_vdb_t * vdb_act = lv_vdb_get(); + if(!vdb_act) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Don't start a new flush while the previous is not finished*/ +#if LV_VDB_DOUBLE + while(vdb_flushing); +#endif /*LV_VDB_DOUBLE*/ + + vdb_flushing = true; + + /*Flush the rendered content to the display*/ + lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf); + + +#if LV_VDB_DOUBLE + /*Make the other VDB active. The content of the current will be kept until the next flush*/ + vdb_active++; + vdb_active &= 0x1; + + /*If the screen is transparent initialize it when the new VDB is selected*/ +# if LV_COLOR_SCREEN_TRANSP + memset(vdb[vdb_active].buf, 0x00, LV_VDB_SIZE_IN_BYTES); +# endif /*LV_COLOR_SCREEN_TRANSP*/ + +#endif /*#if LV_VDB_DOUBLE*/ + +} + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2) +{ +#if LV_VDB_DOUBLE == 0 + (void) buf2; /*unused*/ + vdb.buf = buf1; +#else + vdb[0].buf = buf1; + vdb[1].buf = buf2; +#endif +} + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +LV_ATTRIBUTE_FLUSH_READY void lv_flush_ready(void) +{ + vdb_flushing = false; + + /*If the screen is transparent initialize it when the flushing is ready*/ +#if LV_VDB_DOUBLE == 0 && LV_COLOR_SCREEN_TRANSP + memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES); +#endif +} + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void) +{ +#if LV_VDB_DOUBLE == 0 + return &vdb; +#else + return &vdb[vdb_active]; +#endif +} + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void) +{ +#if LV_VDB_DOUBLE == 0 + return &vdb; +#else + return &vdb[(vdb_active + 1) & 0x1]; +#endif +} + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void) +{ + return vdb_flushing; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#else + +/** + * Just for compatibility + */ +void lv_flush_ready(void) +{ + /*Do nothing. It is used only for VDB*/ +} +#endif diff --git a/bdk/libs/lvgl/lv_core/lv_vdb.h b/bdk/libs/lvgl/lv_core/lv_vdb.h new file mode 100644 index 0000000..e94ba19 --- /dev/null +++ b/bdk/libs/lvgl/lv_core/lv_vdb.h @@ -0,0 +1,119 @@ +/** + * @file lv_vdb.h + * + */ + +#ifndef LV_VDB_H +#define LV_VDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ + +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */ +#endif + + +#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0) +#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required" +#endif + + +/* The size of VDB in bytes. + * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes + * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up. + * E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/ +#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + lv_area_t area; + lv_color_t *buf; +} lv_vdb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void); + +/** + * Flush the content of the vdb + */ +void lv_vdb_flush(void); + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +void lv_flush_ready(void); + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void); + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void); + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void); + +/********************** + * MACROS + **********************/ + +#else /*LV_VDB_SIZE != 0*/ + +/*Just for compatibility*/ +void lv_flush_ready(void); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VDB_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw.c b/bdk/libs/lvgl/lv_draw/lv_draw.c new file mode 100644 index 0000000..af374e3 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw.c @@ -0,0 +1,163 @@ +/** + * @file lv_draw.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include +#include "lv_draw.h" +#include "lv_draw_rbasic.h" +#include "lv_draw_vbasic.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_ufs.h" +#include "../lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +#if LV_VDB_SIZE != 0 +void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vpx; +void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vfill; +void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_vletter; +void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) = lv_vmap; +#else +void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rpx; +void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rfill; +void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_rletter; +void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) = lv_rmap; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa) +{ + /* How to calculate the opacity of pixels on the edges which makes the anti-aliasing? + * For example we have a line like this (y = -0.5 * x): + * + * | _ _ + * * * | + * + * Anti-aliased pixels come to the '*' characters + * Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn: + * 1. A real line should start on (0;0) and end on (2;1) + * 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average + * 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average + * 4. The equation: (px_id * 2 + 1) / (segment_width * 2) + * segment_width: the line segment which is being anti-aliased (was 2 in the example) + * px_id: pixel ID from 0 to (segment_width - 1) + * result: [0..1] coverage of the pixel + */ + + /*Accelerate the common segment sizes to avoid division*/ + static const lv_opa_t seg1[1] = {128}; + static const lv_opa_t seg2[2] = {64, 192}; + static const lv_opa_t seg3[3] = {42, 128, 212}; + static const lv_opa_t seg4[4] = {32, 96, 159, 223}; + static const lv_opa_t seg5[5] = {26, 76, 128, 178, 230}; + static const lv_opa_t seg6[6] = {21, 64, 106, 148, 191, 234}; + static const lv_opa_t seg7[7] = {18, 55, 91, 128, 164, 200, 237}; + static const lv_opa_t seg8[8] = {16, 48, 80, 112, 143, 175, 207, 239}; + + static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4, + seg5, seg6, seg7, seg8 + }; + + if(seg == 0) return LV_OPA_TRANSP; + else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * base_opa) >> 8; + else { + return ((px_id * 2 + 1) * base_opa) / (2 * seg); + } + +} + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) +{ + bool aa_inv = false; + if(length < 0) { + aa_inv = true; + length = -length; + } + + lv_coord_t i; + for(i = 0; i < length; i++) { + lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa); + if(aa_inv) px_opa = opa - px_opa; + px_fp(x, y + i, mask, color, px_opa); + } +} + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) +{ + bool aa_inv = false; + if(length < 0) { + aa_inv = true; + length = -length; + } + + lv_coord_t i; + for(i = 0; i < length; i++) { + lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa); + if(aa_inv) px_opa = opa - px_opa; + px_fp(x + i, y, mask, color, px_opa); + } +} + +#endif diff --git a/bdk/libs/lvgl/lv_draw/lv_draw.h b/bdk/libs/lvgl/lv_draw/lv_draw.h new file mode 100644 index 0000000..cf50e98 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw.h @@ -0,0 +1,115 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_core/lv_style.h" +#include "../lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; +typedef uint8_t lv_img_src_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa); + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +#endif + +/********************** + * GLOBAL VARIABLES + **********************/ +extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa); +extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw.mk b/bdk/libs/lvgl/lv_draw/lv_draw.mk new file mode 100644 index 0000000..a384eef --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw.mk @@ -0,0 +1,14 @@ +CSRCS += lv_draw_vbasic.c +CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw +VPATH += :$(LVGL_DIR)/lvgl/lv_draw + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw" diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_arc.c b/bdk/libs/lvgl/lv_draw/lv_draw_arc.c new file mode 100644 index 0000000..525e56b --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_arc.c @@ -0,0 +1,264 @@ +/** + * @file lv_draw_arc.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_arc.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint16_t fast_atan2(int x, int y); +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); +static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end); +static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t thickness = style->line.width; + if(thickness > radius) thickness = radius; + + lv_coord_t r_out = radius; + lv_coord_t r_in = r_out - thickness; + int16_t deg_base; + int16_t deg; + lv_coord_t x_start[4]; + lv_coord_t x_end[4]; + + lv_color_t color = style->line.color; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + + + bool (*deg_test)(uint16_t, uint16_t, uint16_t); + if(start_angle <= end_angle) deg_test = deg_test_norm; + else deg_test = deg_test_inv; + + if(deg_test(270, start_angle, end_angle)) hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa); // Left Middle + if(deg_test(90, start_angle, end_angle)) hor_line(center_x + r_in, center_y, mask, thickness - 1, color, opa); // Right Middle + if(deg_test(180, start_angle, end_angle)) ver_line(center_x, center_y - r_out + 1, mask, thickness - 1, color, opa); // Top Middle + if(deg_test(0, start_angle, end_angle)) ver_line(center_x, center_y + r_in, mask, thickness - 1, color, opa); // Bottom middle + + uint32_t r_out_sqr = r_out * r_out; + uint32_t r_in_sqr = r_in * r_in; + int16_t xi; + int16_t yi; + for(yi = -r_out; yi < 0; yi++) { + x_start[0] = LV_COORD_MIN; + x_start[1] = LV_COORD_MIN; + x_start[2] = LV_COORD_MIN; + x_start[3] = LV_COORD_MIN; + x_end[0] = LV_COORD_MIN; + x_end[1] = LV_COORD_MIN; + x_end[2] = LV_COORD_MIN; + x_end[3] = LV_COORD_MIN; + for(xi = -r_out; xi < 0; xi++) { + + uint32_t r_act_sqr = xi * xi + yi * yi; + if(r_act_sqr > r_out_sqr) continue; + + deg_base = fast_atan2(xi, yi) - 180; + + deg = 180 + deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[0] == LV_COORD_MIN) x_start[0] = xi; + } else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) { + x_end[0] = xi - 1; + } + + deg = 360 - deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[1] == LV_COORD_MIN) x_start[1] = xi; + } else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) { + x_end[1] = xi - 1; + } + + deg = 180 - deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[2] == LV_COORD_MIN) x_start[2] = xi; + } else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) { + x_end[2] = xi - 1; + } + + deg = deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[3] == LV_COORD_MIN) x_start[3] = xi; + } else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) { + x_end[3] = xi - 1; + } + + if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/ + } + + + if(x_start[0] != LV_COORD_MIN) { + if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1; + hor_line(center_x + x_start[0], center_y + yi, mask, x_end[0] - x_start[0], color, opa); + } + + if(x_start[1] != LV_COORD_MIN) { + if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1; + hor_line(center_x + x_start[1], center_y - yi, mask, x_end[1] - x_start[1], color, opa); + } + + if(x_start[2] != LV_COORD_MIN) { + if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1; + hor_line(center_x - x_end[2], center_y + yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa); + } + + if(x_start[3] != LV_COORD_MIN) { + if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1; + hor_line(center_x - x_end[3], center_y - yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa); + } + + +#if LV_ANTIALIAS + /*TODO*/ + +#endif + + } +} + +static uint16_t fast_atan2(int x, int y) +{ + // Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com + // Converts any XY values including 0 to a degree value that should be + // within +/- 1 degree of the accurate value without needing + // large slow trig functions like ArcTan() or ArcCos(). + // NOTE! at least one of the X or Y values must be non-zero! + // This is the full version, for all 4 quadrants and will generate + // the angle in integer degrees from 0-360. + // Any values of X and Y are usable including negative values provided + // they are between -1456 and 1456 so the 16bit multiply does not overflow. + + unsigned char negflag; + unsigned char tempdegree; + unsigned char comp; + unsigned int degree; // this will hold the result + //signed int x; // these hold the XY vector at the start + //signed int y; // (and they will be destroyed) + unsigned int ux; + unsigned int uy; + + // Save the sign flags then remove signs and get XY as unsigned ints + negflag = 0; + if(x < 0) { + negflag += 0x01; // x flag bit + x = (0 - x); // is now + + } + ux = x; // copy to unsigned var before multiply + if(y < 0) { + negflag += 0x02; // y flag bit + y = (0 - y); // is now + + } + uy = y; // copy to unsigned var before multiply + + // 1. Calc the scaled "degrees" + if(ux > uy) { + degree = (uy * 45) / ux; // degree result will be 0-45 range + negflag += 0x10; // octant flag bit + } else { + degree = (ux * 45) / uy; // degree result will be 0-45 range + } + + // 2. Compensate for the 4 degree error curve + comp = 0; + tempdegree = degree; // use an unsigned char for speed! + if(tempdegree > 22) { // if top half of range + if(tempdegree <= 44) comp++; + if(tempdegree <= 41) comp++; + if(tempdegree <= 37) comp++; + if(tempdegree <= 32) comp++; // max is 4 degrees compensated + } else { // else is lower half of range + if(tempdegree >= 2) comp++; + if(tempdegree >= 6) comp++; + if(tempdegree >= 10) comp++; + if(tempdegree >= 15) comp++; // max is 4 degrees compensated + } + degree += comp; // degree is now accurate to +/- 1 degree! + + // Invert degree if it was X>Y octant, makes 0-45 into 90-45 + if(negflag & 0x10) degree = (90 - degree); + + // 3. Degree is now 0-90 range for this quadrant, + // need to invert it for whichever quadrant it was in + if(negflag & 0x02) { // if -Y + if(negflag & 0x01) // if -Y -X + degree = (180 + degree); + else // else is -Y +X + degree = (180 - degree); + } else { // else is +Y + if(negflag & 0x01) // if +Y -X + degree = (360 - degree); + } + return degree; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x, y + len); + + fill_fp(&area, mask, color, opa); +} + +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x + len, y); + + fill_fp(&area, mask, color, opa); +} + +static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end) +{ + if(deg >= start && deg <= end) return true; + else return false; +} + +static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end) +{ + if(deg >= start || deg <= end) { + return true; + } else return false; +} diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_arc.h b/bdk/libs/lvgl/lv_draw/lv_draw_arc.h new file mode 100644 index 0000000..203eabe --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_arc.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_img.c b/bdk/libs/lvgl/lv_draw/lv_draw_img.c new file mode 100644 index 0000000..5c24aa8 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_img.c @@ -0,0 +1,759 @@ +/** + * @file lv_draw_img.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_img.h" +#include "../lv_misc/lv_fs.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + +static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style); +static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static void lv_img_decoder_close(void); +static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/********************** + * STATIC VARIABLES + **********************/ +static bool decoder_custom; +static const void * decoder_src; +static lv_img_src_t decoder_src_type; +static lv_img_header_t decoder_header; +static const lv_style_t * decoder_style; +#if USE_LV_FILESYSTEM +static lv_fs_file_t decoder_file; +#endif +#if LV_IMG_CF_INDEXED +static lv_color_t decoder_index_map[256]; +#endif + +static lv_img_decoder_info_f_t lv_img_decoder_info_custom; +static lv_img_decoder_open_f_t lv_img_decoder_open_custom; +static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom; +static lv_img_decoder_close_f_t lv_img_decoder_close_custom; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale) +{ + if(src == NULL) { + LV_LOG_WARN("Image draw: src is NULL"); + lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); + lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL); + return; + } + + lv_res_t res; + res = lv_img_draw_core(coords, mask, src, style, opa_scale); + + if(res == LV_RES_INV) { + LV_LOG_WARN("Image draw error"); + lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); + lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL); + return; + } +} + + +/** + * + * @param src + * @param header + * @param style + * @return + */ +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header) +{ + header->always_zero = 0; + /*Try to get info with the custom functions first*/ + if(lv_img_decoder_info_custom) { + lv_res_t custom_res; + custom_res = lv_img_decoder_info_custom(src, header); + if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/ + } + + lv_img_src_t src_type = lv_img_src_get_type(src); + if(src_type == LV_IMG_SRC_VARIABLE) { + header->w = ((lv_img_dsc_t *)src)->header.w; + header->h = ((lv_img_dsc_t *)src)->header.h; + header->cf = ((lv_img_dsc_t *)src)->header.cf; + } +#if USE_LV_FILESYSTEM + else if(src_type == LV_IMG_SRC_FILE) { + lv_fs_file_t file; + lv_fs_res_t res; + uint32_t rn; + res = lv_fs_open(&file, src, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); + } + + /*Create a dummy header on fs error*/ + if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { + header->w = LV_DPI; + header->h = LV_DPI; + header->cf = LV_IMG_CF_UNKOWN; + } + + lv_fs_close(&file); + } +#endif + else if(src_type == LV_IMG_SRC_SYMBOL) { + /*The size depend on the font but it is unknown here. It should be handled outside of the function*/ + header->w = 1; + header->h = 1; + /* Symbols always have transparent parts. Important because of cover check in the design function. + * The actual value doesn't matter because lv_draw_label will draw it*/ + header->cf = LV_IMG_CF_ALPHA_1BIT; + } else { + LV_LOG_WARN("Image get info found unknown src type"); + return false; + } + return true; + +} + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf) +{ + uint8_t px_size = 0; + + switch(cf) { + case LV_IMG_CF_UNKOWN: + case LV_IMG_CF_RAW: + px_size = 0; + break; + case LV_IMG_CF_TRUE_COLOR: + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: + px_size = LV_COLOR_SIZE; + break; + case LV_IMG_CF_TRUE_COLOR_ALPHA: + px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; + break; + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_ALPHA_1BIT: + px_size = 1; + break; + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_ALPHA_2BIT: + px_size = 2; + break; + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_ALPHA_4BIT: + px_size = 4; + break; + case LV_IMG_CF_INDEXED_8BIT: + case LV_IMG_CF_ALPHA_8BIT: + px_size = 8; + break; + default: + px_size = 0; + break; + } + + return px_size; +} + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) +{ + bool is_chroma_keyed = false; + + switch(cf) { + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: + case LV_IMG_CF_RAW_CHROMA_KEYED: + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: + is_chroma_keyed = true; + break; + default: + is_chroma_keyed = false; + break; + } + + return is_chroma_keyed; +} + + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf) +{ + bool has_alpha = false; + + switch(cf) { + case LV_IMG_CF_TRUE_COLOR_ALPHA: + case LV_IMG_CF_RAW_ALPHA: + case LV_IMG_CF_ALPHA_1BIT: + case LV_IMG_CF_ALPHA_2BIT: + case LV_IMG_CF_ALPHA_4BIT: + case LV_IMG_CF_ALPHA_8BIT: + has_alpha = true; + break; + default: + has_alpha = false; + break; + } + + return has_alpha; +} + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src) +{ + lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN; + + if(src == NULL) return img_src_type; + const uint8_t * u8_p = src; + + /*The first byte shows the type of the image source*/ + if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) { + img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/ + } else if(u8_p[0] >= 0x80) { + img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/ + } else { + img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/ + } + + if (LV_IMG_SRC_UNKNOWN == img_src_type) { + LV_LOG_WARN("lv_img_src_get_type: unknown image type"); + } + + return img_src_type; +} + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp) +{ + lv_img_decoder_info_custom = info_fp; + lv_img_decoder_open_custom = open_fp; + lv_img_decoder_read_line_custom = read_fp; + lv_img_decoder_close_custom = close_fp; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + + +static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale) +{ + + lv_area_t mask_com; /*Common area of mask and coords*/ + bool union_ok; + union_ok = lv_area_intersect(&mask_com, mask, coords); + if(union_ok == false) { + return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ + } + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t) style->image.opa * opa_scale) >> 8; + + lv_img_header_t header; + lv_res_t header_res; + header_res = lv_img_dsc_get_info(src, &header); + if(header_res != LV_RES_OK) { + LV_LOG_WARN("Image draw can't get image info"); + lv_img_decoder_close(); + return LV_RES_INV; + } + + bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf); + bool alpha_byte = lv_img_color_format_has_alpha(header.cf); + + const uint8_t * img_data = lv_img_decoder_open(src, style); + if(img_data == LV_IMG_DECODER_OPEN_FAIL) { + LV_LOG_WARN("Image draw cannot open the image resource"); + lv_img_decoder_close(); + return LV_RES_INV; + } + + /* The decoder open could open the image and gave the entire uncompressed image. + * Just draw it!*/ + if(img_data) { + map_fp(coords, mask, img_data, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense); + } + /* The whole uncompressed image is not available. Try to read it line-by-line*/ + else { + lv_coord_t width = lv_area_get_width(&mask_com); + +#if LV_COMPILER_VLA_SUPPORTED + uint8_t buf[(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1))]; +#else + uint8_t buf[LV_HOR_RES * ((LV_COLOR_DEPTH >> 3) + 1)]; /*+1 because of the possible alpha byte*/ +#endif + lv_area_t line; + lv_area_copy(&line, &mask_com); + lv_area_set_height(&line, 1); + lv_coord_t x = mask_com.x1 - coords->x1; + lv_coord_t y = mask_com.y1 - coords->y1; + lv_coord_t row; + lv_res_t read_res; + for(row = mask_com.y1; row <= mask_com.y2; row++) { + read_res = lv_img_decoder_read_line(x, y, width, buf); + if(read_res != LV_RES_OK) { + lv_img_decoder_close(); + LV_LOG_WARN("Image draw can't read the line"); + return LV_RES_INV; + } + map_fp(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense); + line.y1++; + line.y2++; + y++; + } + } + + lv_img_decoder_close(); + + return LV_RES_OK; +} + + +static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style) +{ + decoder_custom = false; + + /*Try to open with the custom functions first*/ + if(lv_img_decoder_open_custom) { + const uint8_t * custom_res; + custom_res = lv_img_decoder_open_custom(src, style); + if(custom_res != LV_IMG_DECODER_OPEN_FAIL) { + decoder_custom = true; /*Mark that custom decoder function should be used for this img source.*/ + return custom_res; /*Custom open supported this source*/ + } + } + + decoder_src = src; + decoder_style = style; + decoder_src_type = lv_img_src_get_type(src); + + lv_res_t header_res; + header_res = lv_img_dsc_get_info(src, &decoder_header); + if(header_res == LV_RES_INV) { + decoder_src = NULL; + decoder_src_type = LV_IMG_SRC_UNKNOWN; + LV_LOG_WARN("Built-in image decoder can't get the header info"); + return LV_IMG_DECODER_OPEN_FAIL; + } + + /*Open the file if it's a file*/ + if(decoder_src_type == LV_IMG_SRC_FILE) { +#if USE_LV_FILESYSTEM + lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder can't open the file"); + return LV_IMG_DECODER_OPEN_FAIL; + } +#else + LV_LOG_WARN("Image built-in decoder can read file because USE_LV_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + + + /*Process the different color formats*/ + lv_img_cf_t cf = decoder_header.cf; + if(cf == LV_IMG_CF_TRUE_COLOR || + cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's pointer*/ + return ((lv_img_dsc_t *)decoder_src)->data; + } else { + /*If it's file it need to be read line by line later*/ + return NULL; + } + } else if(cf == LV_IMG_CF_INDEXED_1BIT || + cf == LV_IMG_CF_INDEXED_2BIT || + cf == LV_IMG_CF_INDEXED_4BIT || + cf == LV_IMG_CF_INDEXED_8BIT) { + +#if LV_IMG_CF_INDEXED +#if USE_LV_FILESYSTEM + lv_color32_t palette_file[256]; +#endif + + lv_color32_t * palette_p = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(cf); + uint32_t palette_size = 1 << px_size; + + if(decoder_src_type == LV_IMG_SRC_FILE) { + /*Read the palette from file*/ +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, 4); /*Skip the header*/ + lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL); + palette_p = palette_file; +#else + LV_LOG_WARN("Image built-in decoder can read the palette because USE_LV_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + /*The palette begins in the beginning of the image data. Just point to it.*/ + palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data; + } + + uint32_t i; + for(i = 0; i < palette_size; i++) { + decoder_index_map[i] = LV_COLOR_MAKE(palette_p[i].red, palette_p[i].green, palette_p[i].blue); + } + return NULL; +#else + LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else if(cf == LV_IMG_CF_ALPHA_1BIT || + cf == LV_IMG_CF_ALPHA_2BIT || + cf == LV_IMG_CF_ALPHA_4BIT || + cf == LV_IMG_CF_ALPHA_8BIT) { +#if LV_IMG_CF_ALPHA + return NULL; /*Nothing to process*/ +#else + LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + LV_LOG_WARN("Image decoder open: unknown color format") + return LV_IMG_DECODER_OPEN_FAIL; + } +} + + +static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + /*Try to read the line with the custom functions*/ + if(decoder_custom) { + if(lv_img_decoder_read_line_custom) { + lv_res_t custom_res; + custom_res = lv_img_decoder_read_line_custom(x, y, len, buf); + return custom_res; + } else { + LV_LOG_WARN("Image open with custom decoder but read not supported") + } + return LV_RES_INV; /*It"s an error if not returned earlier*/ + } + + if(decoder_src_type == LV_IMG_SRC_FILE) { +#if USE_LV_FILESYSTEM + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + + lv_fs_res_t res; + + if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR || + decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3; + pos += 4; /*Skip the header*/ + res = lv_fs_seek(&decoder_file, pos); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder seek failed"); + return false; + } + uint32_t btr = len * (px_size >> 3); + uint32_t br = 0; + lv_fs_read(&decoder_file, buf, btr, &br); + if(res != LV_FS_RES_OK || btr != br) { + LV_LOG_WARN("Built-in image decoder read failed"); + return false; + } + } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_2BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_4BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) { + + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_2BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_4BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder read not supports the color format"); + return false; + } +#else + LV_LOG_WARN("Image built-in decoder can't read file because USE_LV_FILESYSTEM = 0"); + return false; +#endif + } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + + if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder not supports the color format"); + return false; + } + } + + return true; +} + +static void lv_img_decoder_close(void) +{ + /*Try to close with the custom functions*/ + if(decoder_custom) { + if(lv_img_decoder_close_custom) lv_img_decoder_close_custom(); + return; + } + + /*It was opened with built-in decoder*/ + if(decoder_src) { +#if USE_LV_FILESYSTEM + if(decoder_src_type == LV_IMG_SRC_FILE) { + lv_fs_close(&decoder_file); + } +#endif + decoder_src_type = LV_IMG_SRC_UNKNOWN; + decoder_src = NULL; + } +} + +static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + +#if LV_IMG_CF_ALPHA + const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + + /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ + lv_color_t bg_color = decoder_style->image.color; + lv_coord_t i; + for(i = 0; i < len; i++) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; +#elif LV_COLOR_DEPTH == 32 + *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; +#else +#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" +#endif + } + + const lv_opa_t * opa_table = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + uint32_t ofs = 0; + int8_t pos = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_ALPHA_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + pos = 7 - (x & 0x7); + opa_table = alpha1_opa_table; + break; + case LV_IMG_CF_ALPHA_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + pos = 6 - ((x & 0x3) * 2); + opa_table = alpha2_opa_table; + break; + case LV_IMG_CF_ALPHA_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + pos = 4 - ((x & 0x1) * 4); + opa_table = alpha4_opa_table; + break; + case LV_IMG_CF_ALPHA_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + pos = 0; + break; + } + +#if USE_LV_FILESYSTEM +# if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +# else + uint8_t fs_buf[LV_HOR_RES]; +# endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN("Image built-in alpha line reader can't read file because USE_LV_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + + uint8_t byte_act = 0; + uint8_t val_act; + for(i = 0; i < len; i ++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; + +#else + LV_LOG_WARN("Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + +static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + +#if LV_IMG_CF_INDEXED + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + int8_t pos = 0; + uint32_t ofs = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_INDEXED_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + ofs += 8; /*Skip the palette*/ + pos = 7 - (x & 0x7); + break; + case LV_IMG_CF_INDEXED_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + ofs += 16; /*Skip the palette*/ + pos = 6 - ((x & 0x3) * 2); + break; + case LV_IMG_CF_INDEXED_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + ofs += 64; /*Skip the palette*/ + pos = 4 - ((x & 0x1) * 4); + break; + case LV_IMG_CF_INDEXED_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + ofs += 1024; /*Skip the palette*/ + pos = 0; + break; + } + +#if USE_LV_FILESYSTEM +# if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +# else + uint8_t fs_buf[LV_HOR_RES]; +# endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN("Image built-in indexed line reader can't read file because USE_LV_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + lv_coord_t i; + lv_color_t * cbuf = (lv_color_t *) buf; + for(i = 0; i < len; i ++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + cbuf[i] = decoder_index_map[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; +#else + LV_LOG_WARN("Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_img.h b/bdk/libs/lvgl/lv_draw/lv_draw_img.h new file mode 100644 index 0000000..31ed827 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_img.h @@ -0,0 +1,167 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1)) + +/********************** + * TYPEDEFS + **********************/ +struct _lv_img_t; + +typedef struct { + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/ + + uint32_t reserved :2; /*Reserved to be used later*/ + + uint32_t w:11; /*Width of the image map*/ + uint32_t h:11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y startt y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(void); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp); + +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf); + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_label.c b/bdk/libs/lvgl/lv_draw/lv_draw_label.c new file mode 100644 index 0000000..0744ff1 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_label.c @@ -0,0 +1,264 @@ +/** + * @file lv_draw_label.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_label.h" +#include "lv_draw_rbasic.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LABEL_RECOLOR_PAR_LENGTH 6 + +/********************** + * TYPEDEFS + **********************/ +enum { + CMD_STATE_WAIT, + CMD_STATE_PAR, + CMD_STATE_IN, +}; +typedef uint8_t cmd_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint8_t hex_char_to_num(char hex); + +/********************** + * STATIC VARIABLES + **********************/ + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset) +{ + const lv_font_t * font = style->text.font; + lv_coord_t w; + if((flag & LV_TXT_FLAG_EXPAND) == 0) { + /*Normally use the label's width as width*/ + w = lv_area_get_width(coords); + } else { + /*If EXAPND is enabled then not limit the text's width to the object's width*/ + lv_point_t p; + lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); + w = p.x; + } + + lv_coord_t line_height = lv_font_get_height(font) + style->text.line_space; + + + /*Init variables for the first line*/ + lv_coord_t line_width = 0; + lv_point_t pos; + pos.x = coords->x1; + pos.y = coords->y1; + + lv_coord_t x_ofs = 0; + lv_coord_t y_ofs = 0; + if(offset != NULL) { + x_ofs = offset->x; + y_ofs = offset->y; + pos.y += y_ofs; + } + + uint32_t line_start = 0; + uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag); + + /*Go the first visible line*/ + while(pos.y + line_height < mask->y1) { + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); + pos.y += line_height; + + if(txt[line_start] == '\0') return; + } + + /*Align to middle*/ + if(flag & LV_TXT_FLAG_CENTER) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + + pos.x += (lv_area_get_width(coords) - line_width) / 2; + + } + /*Align to the right*/ + else if(flag & LV_TXT_FLAG_RIGHT) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t) style->text.opa * opa_scale) >> 8; + + cmd_state_t cmd_state = CMD_STATE_WAIT; + uint32_t i; + uint16_t par_start = 0; + lv_color_t recolor; + lv_coord_t letter_w; + + /*Real draw need a background color for higher bpp letter*/ +#if LV_VDB_SIZE == 0 + lv_rletter_set_background(style->body.main_color); +#endif + + + /*Write out all lines*/ + while(txt[line_start] != '\0') { + if(offset != NULL) { + pos.x += x_ofs; + } + /*Write all letter of a line*/ + cmd_state = CMD_STATE_WAIT; + i = line_start; + uint32_t letter; + while(i < line_end) { + letter = lv_txt_encoded_next(txt, &i); + + /*Handle the re-color command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) { + if(cmd_state == CMD_STATE_WAIT) { /*Start char*/ + par_start = i; + cmd_state = CMD_STATE_PAR; + continue; + } else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */ + cmd_state = CMD_STATE_WAIT; + } else if(cmd_state == CMD_STATE_IN) { /*Command end */ + cmd_state = CMD_STATE_WAIT; + continue; + } + } + + /*Skip the color parameter and wait the space after it*/ + if(cmd_state == CMD_STATE_PAR) { + if(letter == ' ') { + /*Get the parameter*/ + if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) { + char buf[LABEL_RECOLOR_PAR_LENGTH + 1]; + memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH); + buf[LABEL_RECOLOR_PAR_LENGTH] = '\0'; + int r, g, b; + r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]); + g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]); + b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]); + recolor = LV_COLOR_MAKE(r, g, b); + } else { + recolor.full = style->text.color.full; + } + cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + continue; + } + } + + lv_color_t color = style->text.color; + + if(cmd_state == CMD_STATE_IN) color = recolor; + + letter_fp(&pos, mask, font, letter, color, opa); + letter_w = lv_font_get_width(font, letter); + + if(letter_w > 0){ + pos.x += letter_w + style->text.letter_space; + } + } + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); + + pos.x = coords->x1; + /*Align to middle*/ + if(flag & LV_TXT_FLAG_CENTER) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + + pos.x += (lv_area_get_width(coords) - line_width) / 2; + + } + /*Align to the right*/ + else if(flag & LV_TXT_FLAG_RIGHT) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + /*Go the next line position*/ + pos.y += line_height; + + if(pos.y > mask->y2) return; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert a hexadecimal characters to a number (0..15) + * @param hex Pointer to a hexadecimal character (0..9, A..F) + * @return the numerical value of `hex` or 0 on error + */ +static uint8_t hex_char_to_num(char hex) +{ + uint8_t result = 0; + + if(hex >= '0' && hex <= '9') { + result = hex - '0'; + } + else { + if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ + + switch(hex) { + case 'A': + result = 10; + break; + case 'B': + result = 11; + break; + case 'C': + result = 12; + break; + case 'D': + result = 13; + break; + case 'E': + result = 14; + break; + case 'F': + result = 15; + break; + default: + result = 0; + break; + } + } + + return result; +} diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_label.h b/bdk/libs/lvgl/lv_draw/lv_draw_label.h new file mode 100644 index 0000000..8798573 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_label.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_line.c b/bdk/libs/lvgl/lv_draw/lv_draw_line.c new file mode 100644 index 0000000..6e72ff4 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_line.c @@ -0,0 +1,607 @@ +/** + * @file lv_draw_line.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_draw.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#if LV_COMPILER_VLA_SUPPORTED == 0 +#define LINE_MAX_WIDTH 64 +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_point_t p1; + lv_point_t p2; + lv_point_t p_act; + lv_coord_t dx; + lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/ + lv_coord_t dy; + lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/ + lv_coord_t err; + lv_coord_t e2; + bool hor; /*Rather horizontal or vertical*/ +} line_draw_t; + +typedef struct { + lv_coord_t width; + lv_coord_t width_1; + lv_coord_t width_half; +} line_width_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2); +static bool line_next(line_draw_t * line); +static bool line_next_y(line_draw_t * line); +static bool line_next_x(line_draw_t * line); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale) +{ + + if(style->line.width == 0) return; + if(point1->x == point2->x && point1->y == point2->y) return; + + line_draw_t main_line; + lv_point_t p1; + lv_point_t p2; + + /*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/ + + if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) { + + /*Steps less in y then x -> rather horizontal*/ + if(point1->x < point2->x) { + p1.x = point1->x; + p1.y = point1->y; + p2.x = point2->x; + p2.y = point2->y; + } else { + p1.x = point2->x; + p1.y = point2->y; + p2.x = point1->x; + p2.y = point1->y; + } + } else { + /*Steps less in x then y -> rather vertical*/ + if(point1->y < point2->y) { + p1.x = point1->x; + p1.y = point1->y; + p2.x = point2->x; + p2.y = point2->y; + } else { + p1.x = point2->x; + p1.y = point2->y; + p2.x = point1->x; + p2.y = point1->y; + } + } + + line_init(&main_line, &p1, &p2); + + + /*Special case draw a horizontal line*/ + if(main_line.p1.y == main_line.p2.y) { + line_draw_hor(&main_line, mask, style, opa_scale); + } + /*Special case draw a vertical line*/ + else if(main_line.p1.x == main_line.p2.x) { + line_draw_ver(&main_line, mask, style, opa_scale); + } + /*Arbitrary skew line*/ + else { + bool dir_ori = false; +#if LV_ANTIALIAS + lv_point_t p_tmp; + + if(main_line.hor) { + if(main_line.p1.y < main_line.p2.y) { + dir_ori = true; + p_tmp.x = main_line.p2.x; + p_tmp.y = main_line.p2.y - 1; + line_init(&main_line, &p1, &p_tmp); + main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ + } + else if(main_line.p1.y > main_line.p2.y) { + dir_ori = false; + p_tmp.x = main_line.p2.x; + p_tmp.y = main_line.p2.y + 1; + line_init(&main_line, &p1, &p_tmp); + main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ + } + } + else { + if(main_line.p1.x < main_line.p2.x) { + dir_ori = true; + p_tmp.x = main_line.p2.x - 1; + p_tmp.y = main_line.p2.y; + line_init(&main_line, &p1, &p_tmp); + main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ + } + else if(main_line.p1.x > main_line.p2.x) { + dir_ori = false; + p_tmp.x = main_line.p2.x + 1; + p_tmp.y = main_line.p2.y; + line_init(&main_line, &p1, &p_tmp); + main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ + } + } +#endif + line_draw_skew(&main_line, dir_ori, mask, style, opa_scale); + } +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + + +static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t width = style->line.width - 1; + lv_coord_t width_half = width >> 1; + lv_coord_t width_1 = width & 0x1; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + lv_area_t act_area; + act_area.x1 = main_line->p1.x; + act_area.x2 = main_line->p2.x; + act_area.y1 = main_line->p1.y - width_half - width_1; + act_area.y2 = main_line->p2.y + width_half ; + + lv_area_t draw_area; + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + fill_fp(&draw_area, mask, style->line.color, opa); +} + +static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t width = style->line.width - 1; + lv_coord_t width_half = width >> 1; + lv_coord_t width_1 = width & 0x1; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + + lv_area_t act_area; + act_area.x1 = main_line->p1.x - width_half; + act_area.x2 = main_line->p2.x + width_half + width_1; + act_area.y1 = main_line->p1.y; + act_area.y2 = main_line->p2.y; + + lv_area_t draw_area; + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + fill_fp(&draw_area, mask, style->line.color, opa); +} + +static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + lv_point_t vect_main, vect_norm; + vect_main.x = main_line->p2.x - main_line->p1.x; + vect_main.y = main_line->p2.y - main_line->p1.y; + + if(main_line->hor) { + if(main_line->p1.y < main_line->p2.y + dir_ori) { + vect_norm.x = - vect_main.y; + vect_norm.y = vect_main.x; + } else { + vect_norm.x = vect_main.y; + vect_norm.y = -vect_main.x; + } + } else { + if(main_line->p1.x < main_line->p2.x + dir_ori) { + vect_norm.x = vect_main.y; + vect_norm.y = - vect_main.x; + } else { + vect_norm.x = - vect_main.y; + vect_norm.y = vect_main.x; + } + } + + /* In case of a short but tick line the perpendicular ending is longer then the real line. + * it would break the calculations so make the normal vector larger*/ + vect_norm.x = vect_norm.x << 4; + vect_norm.y = vect_norm.y << 4; + + lv_coord_t width; + width = style->line.width; + + /* The pattern stores the points of the line ending. It has the good direction and length. + * The worth case is the 45° line where pattern can have 1.41 x `width` points*/ +#if LV_COMPILER_VLA_SUPPORTED + lv_point_t pattern[width * 2]; +#else + lv_point_t pattern[LINE_MAX_WIDTH]; +#endif + lv_coord_t i = 0; + + /*Create a perpendicular pattern (a small line)*/ + if(width != 0) { + line_draw_t pattern_line; + lv_point_t p0 = {0, 0}; + line_init(&pattern_line, &p0, &vect_norm); + + uint32_t width_sqr = width * width; + /* Run for a lot of times. Meanwhile the real width will be determined as well */ + for(i = 0; i < (lv_coord_t)sizeof(pattern); i ++) { + pattern[i].x = pattern_line.p_act.x; + pattern[i].y = pattern_line.p_act.y; + + /*Finish the pattern line if it's length equal to the desired width (Use Pythagoras theorem)*/ + uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y; + if(sqr >= width_sqr) { + width = i; +#if LV_ANTIALIAS + width--; +#endif + break; + } + + line_next(&pattern_line); + } + } + +#if LV_ANTIALIAS + lv_coord_t width_safe = width; + if(width == 0) width_safe = 1; + + lv_coord_t aa_last_corner; + aa_last_corner = 0; +#endif + + lv_coord_t x_center_ofs = 0; + lv_coord_t y_center_ofs = 0; + + if(width != 0) { + x_center_ofs = pattern[width - 1].x / 2; + y_center_ofs = pattern[width - 1].y / 2; + } + else { + if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y --; + if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x --; + } + + /* Make the coordinates relative to the center */ + for(i = 0; i < width; i++) { + pattern[i].x -= x_center_ofs; + pattern[i].y -= y_center_ofs; +#if LV_ANTIALIAS + if(i != 0) { + if(main_line->hor) { + if(pattern[i - 1].x != pattern[i].x) { + lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y; + if(main_line->sy < 0) { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, + -seg_w, mask, style->line.color, opa); + } else { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y, + -seg_w, mask, style->line.color, opa); + } + aa_last_corner = i; + } + } else { + if(pattern[i - 1].y != pattern[i].y) { + lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x; + if(main_line->sx < 0) { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p2.y + pattern[aa_last_corner].y + 1, + -seg_w, mask, style->line.color, opa); + } else { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1, + -seg_w, mask, style->line.color, opa); + } + aa_last_corner = i; + } + } + + } +#endif + } + + + +#if LV_ANTIALIAS + /*Add the last part of anti-aliasing for the perpendicular ending*/ + if(width != 0) { /*Due to rounding error with very thin lines it looks ugly*/ + if(main_line->hor) { + lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y; + if(main_line->sy < 0) { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w, + seg_w + main_line->sy, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w, + -(seg_w + main_line->sy), mask, style->line.color, opa); + + } else { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y, + seg_w + main_line->sy, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y, + -(seg_w + main_line->sy), mask, style->line.color, opa); + } + } else { + lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x; + if(main_line->sx < 0) { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w + main_line->sx, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, main_line->p2.y + pattern[aa_last_corner].y + 1, + -(seg_w + main_line->sx), mask, style->line.color, opa); + + } else { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w + main_line->sx, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1, + -(seg_w + main_line->sx), mask, style->line.color, opa); + } + + } + } +#endif + +#if LV_ANTIALIAS + + /*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/ + lv_coord_t aa_shift1; + lv_coord_t aa_shift2; + + if(main_line->hor == false) { + if(main_line->sx < 0) { + aa_shift1 = -1; + aa_shift2 = width == 0 ? 0 : aa_shift1; + } else { + aa_shift2 = 1; + aa_shift1 = width == 0 ? 0 : aa_shift2; + } + } else { + if(main_line->sy < 0) { + aa_shift1 = -1; + aa_shift2 = width == 0 ? 0 : aa_shift1; + } else { + aa_shift2 = 1; + aa_shift1 = width == 0 ? 0 : aa_shift2; + } + } + +#endif + + volatile lv_point_t prev_p; + prev_p.x = main_line->p1.x; + prev_p.y = main_line->p1.y; + lv_area_t draw_area; + bool first_run = true; + + if(main_line->hor) { + while(line_next_y(main_line)) { + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1; + draw_area.y2 = draw_area.y1; + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in y one pixel remains empty on every corner (don't do this on the first segment ) */ + if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { + px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, + -(main_line->p_act.x - prev_p.x), mask, style->line.color, opa); + lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2, + main_line->p_act.x - prev_p.x, mask, style->line.color, opa); +#endif + + first_run = false; + + prev_p.x = main_line->p_act.x; + prev_p.y = main_line->p_act.y; + } + + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x; + draw_area.y2 = draw_area.y1; + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in y one pixel remains empty on every corner */ + if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { + px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, + -(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa); + lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2, + main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa); +#endif + } + /*Rather a vertical line*/ + else { + + while(line_next_x(main_line)) { + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1; + draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1; + + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in x one pixel remains empty on every corner (don't do this on the first segment ) */ + if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { + px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); + } + + } + +#if LV_ANTIALIAS + lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, + -(main_line->p_act.y - prev_p.y), mask, style->line.color, opa); + lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y, + main_line->p_act.y - prev_p.y, mask, style->line.color, opa); +#endif + + first_run = false; + + prev_p.x = main_line->p_act.x; + prev_p.y = main_line->p_act.y; + } + + /*Draw the last part*/ + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1; + draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y; + + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in x one pixel remains empty on every corner */ + if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { + px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, + -(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa); + lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y, + main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa); +#endif + } +} + + +static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2) +{ + line->p1.x = p1->x; + line->p1.y = p1->y; + line->p2.x = p2->x; + line->p2.y = p2->y; + + line->dx = LV_MATH_ABS(line->p2.x - line->p1.x); + line->sx = line->p1.x < line->p2.x ? 1 : -1; + line->dy = LV_MATH_ABS(line->p2.y - line->p1.y); + line->sy = line->p1.y < line->p2.y ? 1 : -1; + line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2; + line->e2 = 0; + line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/ + + line->p_act.x = line->p1.x; + line->p_act.y = line->p1.y; +} + +static bool line_next(line_draw_t * line) +{ + if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false; + line->e2 = line->err; + if(line->e2 > -line->dx) { + line->err -= line->dy; + line->p_act.x += line->sx; + } + if(line->e2 < line->dy) { + line->err += line->dx; + line->p_act.y += line->sy; + } + return true; +} + +/** + * Iterate until step one in y direction. + * @param line + * @return + */ +static bool line_next_y(line_draw_t * line) +{ + lv_coord_t last_y = line->p_act.y; + + do { + if(!line_next(line)) return false; + } while(last_y == line->p_act.y); + + return true; + +} + +/** + * Iterate until step one in x direction. + * @param line + * @return + */ +static bool line_next_x(line_draw_t * line) +{ + lv_coord_t last_x = line->p_act.x; + + do { + if(!line_next(line)) return false; + } while(last_x == line->p_act.x); + + return true; + +} + diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_line.h b/bdk/libs/lvgl/lv_draw/lv_draw_line.h new file mode 100644 index 0000000..4269475 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_line.h @@ -0,0 +1,49 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c new file mode 100644 index 0000000..369adf5 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c @@ -0,0 +1,269 @@ +/** + * @file lv_draw_rbasic.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_rbasic.h" +#if USE_LV_REAL_DRAW != 0 + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_font.h" +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_color_t letter_bg_color; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Put a pixel to the display + * @param x x coordinate of the pixel + * @param y y coordinate of the pixel + * @param mask_p the pixel will be drawn on this area + * @param color color of the pixel + * @param opa opacity (ignored, only for compatibility with lv_vpx) + */ +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa) +{ + (void)opa; /*Opa is used only for compatibility with lv_vpx*/ + + lv_area_t area; + area.x1 = x; + area.y1 = y; + area.x2 = x; + area.y2 = y; + + lv_rfill(&area, mask_p, color, LV_OPA_COVER); +} + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa) +{ + + (void)opa; /*Opa is used only for compatibility with lv_vfill*/ + + lv_area_t masked_area; + bool union_ok = true; + + if(mask_p != NULL) { + union_ok = lv_area_intersect(&masked_area, cords_p, mask_p); + } else { + lv_area_t scr_area; + lv_area_set(&scr_area, 0, 0, LV_HOR_RES - 1, LV_VER_RES - 1); + union_ok = lv_area_intersect(&masked_area, cords_p, &scr_area); + } + + if(union_ok != false) { + lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color); + } +} + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa) +{ + (void)opa; /*Opa is used only for compatibility with lv_vletter*/ + + static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + static uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + + if(font_p == NULL) return; + + uint8_t letter_w = lv_font_get_width(font_p, letter); + uint8_t letter_h = lv_font_get_height(font_p); + uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/ + uint8_t * bpp_opa_table; + uint8_t mask_init; + uint8_t mask; + + switch(bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + mask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + mask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + mask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + mask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + return; /*Invalid bpp. Can't render the letter*/ + } + + const uint8_t * map_p = lv_font_get_bitmap(font_p, letter); + + if(map_p == NULL) return; + + /*If the letter is completely out of mask don't draw it */ + if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 || + pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return; + + lv_coord_t col, row; + uint8_t col_bit; + uint8_t col_byte_cnt; + uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(letter_w & 0x7) width_byte_scr++; + uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/ + if((letter_w * bpp) & 0x7) width_byte_bpp++; + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_p->x >= mask_p->x1 ? 0 : mask_p->x1 - pos_p->x; + lv_coord_t col_end = pos_p->x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_p->x + 1; + lv_coord_t row_start = pos_p->y >= mask_p->y1 ? 0 : mask_p->y1 - pos_p->y; + lv_coord_t row_end = pos_p->y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_p->y + 1; + + /*Move on the map too*/ + map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3); + + uint8_t letter_px; + for(row = row_start; row < row_end; row ++) { + col_byte_cnt = 0; + col_bit = (col_start * bpp) % 8; + mask = mask_init >> col_bit; + for(col = col_start; col < col_end; col ++) { + letter_px = (*map_p & mask) >> (8 - col_bit - bpp); + if(letter_px != 0) { + lv_rpx(pos_p->x + col, pos_p->y + row, mask_p, lv_color_mix(color, letter_bg_color, bpp == 8 ? letter_px : bpp_opa_table[letter_px]), LV_OPA_COVER); + } + + if(col_bit < 8 - bpp) { + col_bit += bpp; + mask = mask >> bpp; + } else { + col_bit = 0; + col_byte_cnt ++; + mask = mask_init; + map_p ++; + } + } + + map_p += (width_byte_bpp) - col_byte_cnt; + } +} + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color) +{ + letter_bg_color = color; +} + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) +{ + if(alpha_byte) return; /*Pixel level opacity i not supported in real map drawing*/ + + (void)opa; /*opa is used only for compatibility with lv_vmap*/ + lv_area_t masked_a; + bool union_ok; + + union_ok = lv_area_intersect(&masked_a, cords_p, mask_p); + + /*If there are common part of the mask and map then draw the map*/ + if(union_ok == false) return; + + /*Go to the first pixel*/ + lv_coord_t map_width = lv_area_get_width(cords_p); + map_p += (masked_a.y1 - cords_p->y1) * map_width * sizeof(lv_color_t); + map_p += (masked_a.x1 - cords_p->x1) * sizeof(lv_color_t); + + lv_coord_t row; + if(recolor_opa == LV_OPA_TRANSP && chroma_key == false) { + lv_coord_t mask_w = lv_area_get_width(&masked_a) - 1; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t *)map_p); + map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/ + } + } else { + lv_color_t chroma_key_color = LV_COLOR_TRANSP; + lv_coord_t col; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = masked_a.x1; col <= masked_a.x2; col++) { + lv_color_t * px_color = (lv_color_t *) &map_p[(uint32_t)(col - masked_a.x1) * sizeof(lv_color_t)]; + + if(chroma_key && chroma_key_color.full == px_color->full) continue; + + if(recolor_opa != LV_OPA_TRANSP) { + lv_color_t recolored_px = lv_color_mix(recolor, *px_color, recolor_opa); + + lv_rpx(col, row, mask_p, recolored_px, LV_OPA_COVER); + } else { + lv_rpx(col, row, mask_p, *px_color, LV_OPA_COVER); + } + + } + map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/ + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h new file mode 100644 index 0000000..b1d62f3 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rbasic..h + * + */ + +#ifndef LV_DRAW_RBASIC_H +#define LV_DRAW_RBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_REAL_DRAW != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color); + + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_rect.c b/bdk/libs/lvgl/lv_draw/lv_draw_rect.c new file mode 100644 index 0000000..5b4ef16 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_rect.c @@ -0,0 +1,1435 @@ +/** + * @file lv_draw_rect.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "../lv_misc/lv_circ.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD 5 /*Circle segment greater then this value will be anti-aliased by a non-linear (cos) opacity mapping*/ + +#define SHADOW_OPA_EXTRA_PRECISION 8 /*Calculate with 2^x bigger shadow opacity values to avoid rounding errors*/ +#define SHADOW_BOTTOM_AA_EXTRA_RADIUS 3 /*Add extra radius with LV_SHADOW_BOTTOM to cover anti-aliased corners*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +#if USE_LV_SHADOW && LV_VDB_SIZE +static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map); +#endif + +static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h); + +#if LV_ANTIALIAS +static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return; + +#if USE_LV_SHADOW && LV_VDB_SIZE + if(style->body.shadow.width != 0) { + lv_draw_shadow(coords, mask, style, opa_scale); + } +#endif + if(style->body.empty == 0 && style->body.opa >= LV_OPA_MIN) { + lv_draw_rect_main_mid(coords, mask, style, opa_scale); + + if(style->body.radius != 0) { + lv_draw_rect_main_corner(coords, mask, style, opa_scale); + } + } + + if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE && style->body.border.opa >= LV_OPA_MIN) { + lv_draw_rect_border_straight(coords, mask, style, opa_scale); + + if(style->body.radius != 0) { + lv_draw_rect_border_corner(coords, mask, style, opa_scale); + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Draw the middle part (rectangular) of a rectangle + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param rects_p pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_color_t mcolor = style->body.main_color; + lv_color_t gcolor = style->body.grad_color; + uint8_t mix; + lv_coord_t height = lv_area_get_height(coords); + lv_coord_t width = lv_area_get_width(coords); + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + + radius = lv_draw_cont_radius_corr(radius, width, height); + + /*If the radius is too big then there is no body*/ + if(radius > height / 2) return; + + lv_area_t work_area; + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + + if(mcolor.full == gcolor.full) { + work_area.y1 = coords->y1 + radius; + work_area.y2 = coords->y2 - radius; + + if(style->body.radius != 0) { +#if LV_ANTIALIAS + work_area.y1 += 2; + work_area.y2 -= 2; +#else + work_area.y1 += 1; + work_area.y2 -= 1; +#endif + } + + fill_fp(&work_area, mask, mcolor, opa); + } else { + lv_coord_t row; + lv_coord_t row_start = coords->y1 + radius; + lv_coord_t row_end = coords->y2 - radius; + lv_color_t act_color; + + if(style->body.radius != 0) { +#if LV_ANTIALIAS + row_start += 2; + row_end -= 2; +#else + row_start += 1; + row_end -= 1; +#endif + } + if(row_start < 0) row_start = 0; + + for(row = row_start; row <= row_end; row ++) { + work_area.y1 = row; + work_area.y2 = row; + mix = (uint32_t)((uint32_t)(coords->y2 - work_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + + fill_fp(&work_area, mask, act_color, opa); + } + } +} +/** + * Draw the top and bottom parts (corners) of a rectangle + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param rects_p pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_color_t mcolor = style->body.main_color; + lv_color_t gcolor = style->body.grad_color; + lv_color_t act_color; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + uint8_t mix; + lv_coord_t height = lv_area_get_height(coords); + lv_coord_t width = lv_area_get_width(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + lv_point_t lt_origo; /*Left Top origo*/ + lv_point_t lb_origo; /*Left Bottom origo*/ + lv_point_t rt_origo; /*Right Top origo*/ + lv_point_t rb_origo; /*Left Bottom origo*/ + + lt_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + lb_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + rt_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + rb_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t edge_top_area; + lv_area_t mid_top_area; + lv_area_t mid_bot_area; + lv_area_t edge_bot_area; + + lv_point_t cir; + lv_coord_t cir_tmp; + lv_circ_init(&cir, &cir_tmp, radius); + + /*Init the areas*/ + lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir), + lb_origo.y + LV_CIRC_OCT4_Y(cir), + rb_origo.x + LV_CIRC_OCT1_X(cir), + rb_origo.y + LV_CIRC_OCT1_Y(cir)); + + lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir), + lb_origo.y + LV_CIRC_OCT3_Y(cir), + rb_origo.x + LV_CIRC_OCT2_X(cir), + rb_origo.y + LV_CIRC_OCT2_Y(cir)); + + lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir), + lt_origo.y + LV_CIRC_OCT5_Y(cir), + rt_origo.x + LV_CIRC_OCT8_X(cir), + rt_origo.y + LV_CIRC_OCT8_Y(cir)); + + lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir), + lt_origo.y + LV_CIRC_OCT6_Y(cir), + rt_origo.x + LV_CIRC_OCT7_X(cir), + rt_origo.y + LV_CIRC_OCT7_Y(cir)); +#if LV_ANTIALIAS + /*Store some internal states for anti-aliasing*/ + lv_coord_t out_y_seg_start = 0; + lv_coord_t out_y_seg_end = 0; + lv_coord_t out_x_last = radius; + + lv_color_t aa_color_hor_top; + lv_color_t aa_color_hor_bottom; + lv_color_t aa_color_ver; +#endif + + while(lv_circ_cont(&cir)) { +#if LV_ANTIALIAS != 0 + /*New step in y on the outter circle*/ + if(out_x_last != cir.x) { + out_y_seg_end = cir.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height; + aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix); + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + } + + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa); + + mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height; + aa_color_ver = lv_color_mix(mcolor, gcolor, mix); + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + + aa_color_ver = lv_color_mix(gcolor, mcolor, mix); + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + } + + out_x_last = cir.x; + out_y_seg_start = out_y_seg_end; + } +#endif + uint8_t edge_top_refr = 0; + uint8_t mid_top_refr = 0; + uint8_t mid_bot_refr = 0; + uint8_t edge_bot_refr = 0; + + /* If a new row coming draw the previous + * The y coordinate can remain the same so wait for a new*/ + if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y) mid_bot_refr = 1; + + if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) edge_bot_refr = 1; + + if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) mid_top_refr = 1; + + if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) edge_top_refr = 1; + + /*Draw the areas which are not disabled*/ + if(edge_top_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_top_area, mask, act_color, opa); + } + + if(mid_top_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_top_area, mask, act_color, opa); + } + + if(mid_bot_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_bot_area, mask, act_color, opa); + } + + if(edge_bot_refr != 0) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_bot_area, mask, act_color, opa); + } + + /*Save the current coordinates*/ + lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir), + lb_origo.y + LV_CIRC_OCT4_Y(cir), + rb_origo.x + LV_CIRC_OCT1_X(cir), + rb_origo.y + LV_CIRC_OCT1_Y(cir)); + + lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir), + lb_origo.y + LV_CIRC_OCT3_Y(cir), + rb_origo.x + LV_CIRC_OCT2_X(cir), + rb_origo.y + LV_CIRC_OCT2_Y(cir)); + + lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir), + lt_origo.y + LV_CIRC_OCT5_Y(cir), + rt_origo.x + LV_CIRC_OCT8_X(cir), + rt_origo.y + LV_CIRC_OCT8_Y(cir)); + + lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir), + lt_origo.y + LV_CIRC_OCT6_Y(cir), + rt_origo.x + LV_CIRC_OCT7_X(cir), + rt_origo.y + LV_CIRC_OCT7_Y(cir)); + + lv_circ_next(&cir, &cir_tmp); + } + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_top_area, mask, act_color, opa); + + if(edge_top_area.y1 != mid_top_area.y1) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_top_area, mask, act_color, opa); + } + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_bot_area, mask, act_color, opa); + + if(edge_bot_area.y1 != mid_bot_area.y1) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_bot_area, mask, act_color, opa); + } + + +#if LV_ANTIALIAS + /*The first and the last line is not drawn*/ + edge_top_area.x1 = coords->x1 + radius + 2; + edge_top_area.x2 = coords->x2 - radius - 2; + edge_top_area.y1 = coords->y1; + edge_top_area.y2 = coords->y1; + fill_fp(&edge_top_area, mask, style->body.main_color, opa); + + edge_top_area.y1 = coords->y2; + edge_top_area.y2 = coords->y2; + fill_fp(&edge_top_area, mask, style->body.grad_color, opa); + + /*Last parts of the anti-alias*/ + out_y_seg_end = cir.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height; + aa_color_hor_bottom = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_top = lv_color_mix(mcolor, gcolor, mix); + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa); + + mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height; + aa_color_ver = lv_color_mix(mcolor, gcolor, mix); + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + + aa_color_ver = lv_color_mix(gcolor, mcolor, mix); + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + } + + /*In some cases the last pixel is not drawn*/ + if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) { + aa_p.x = out_x_last; + aa_p.y = out_x_last; + + mix = (uint32_t)((uint32_t)(out_x_last) * 255) / height; + aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix); + + lv_opa_t aa_opa = opa >> 1; + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, aa_color_hor_bottom, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, aa_color_hor_bottom, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, aa_color_hor_top, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, aa_color_hor_top, aa_opa); + } + +#endif + + +} + +/** + * Draw the straight parts of a rectangle border + * @param coords the coordinates of the original rectangle + * @param mask_ the rectangle will be drawn only on this area + * @param rstyle pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + uint16_t bwidth = style->body.border.width; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8; + lv_border_part_t part = style->body.border.part; + lv_color_t color = style->body.border.color; + lv_area_t work_area; + lv_coord_t length_corr = 0; + lv_coord_t corner_size = 0; + + /*the 0 px border width drawn as 1 px, so decrement the b_width*/ + bwidth--; + + radius = lv_draw_cont_radius_corr(radius, width, height); + + if(radius < bwidth) { + length_corr = bwidth - radius - LV_ANTIALIAS; + corner_size = bwidth; + } else { + corner_size = radius + LV_ANTIALIAS; + } + + /*If radius == 0 is a special case*/ + if(style->body.radius == 0) { + /*Left top corner*/ + if(part & LV_BORDER_TOP) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top corner*/ + if(part & LV_BORDER_RIGHT) { + work_area.x1 = coords->x2 - bwidth; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0); + work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0); + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom corner*/ + if(part & LV_BORDER_LEFT) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + bwidth; + work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0); + work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0); + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom corner*/ + if(part & LV_BORDER_BOTTOM) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + return; + } + + /* Modify the corner_size if corner is drawn */ + corner_size ++; + + /*Depending one which part's are drawn modify the area lengths */ + if(part & LV_BORDER_TOP) work_area.y1 = coords->y1 + corner_size; + else work_area.y1 = coords->y1 + radius; + + if(part & LV_BORDER_BOTTOM) work_area.y2 = coords->y2 - corner_size; + else work_area.y2 = coords->y2 - radius; + + /*Left border*/ + if(part & LV_BORDER_LEFT) { + work_area.x1 = coords->x1; + work_area.x2 = work_area.x1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right border*/ + if(part & LV_BORDER_RIGHT) { + work_area.x2 = coords->x2; + work_area.x1 = work_area.x2 - bwidth; + fill_fp(&work_area, mask, color, opa); + } + + work_area.x1 = coords->x1 + corner_size - length_corr; + work_area.x2 = coords->x2 - corner_size + length_corr; + + /*Upper border*/ + if(part & LV_BORDER_TOP) { + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Lower border*/ + if(part & LV_BORDER_BOTTOM) { + work_area.y2 = coords->y2; + work_area.y1 = work_area.y2 - bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Draw the a remaining rectangles if the radius is smaller then bwidth */ + if(length_corr != 0) { + /*Left top correction*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + radius + LV_ANTIALIAS; + work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top correction*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - radius - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom correction*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + radius + LV_ANTIALIAS; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom correction*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - radius - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + } + + /*If radius == 0 one px on the corners are not drawn by main drawer*/ + if(style->body.radius == 0) { + /*Left top corner*/ + if(part & (LV_BORDER_TOP | LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + LV_ANTIALIAS; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top corner*/ + if(part & (LV_BORDER_TOP | LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom corner*/ + if(part & (LV_BORDER_BOTTOM | LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + LV_ANTIALIAS; + work_area.y1 = coords->y2 - LV_ANTIALIAS; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom corner*/ + if(part & (LV_BORDER_BOTTOM | LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - LV_ANTIALIAS; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + } +} + + +/** + * Draw the corners of a rectangle border + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius ; + uint16_t bwidth = style->body.border.width; + lv_color_t color = style->body.border.color; + lv_border_part_t part = style->body.border.part; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8; + /*0 px border width drawn as 1 px, so decrement the bwidth*/ + bwidth--; + +#if LV_ANTIALIAS + bwidth--; /*Because of anti-aliasing the border seems one pixel ticker*/ +#endif + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + lv_point_t lt_origo; /*Left Top origo*/ + lv_point_t lb_origo; /*Left Bottom origo*/ + lv_point_t rt_origo; /*Right Top origo*/ + lv_point_t rb_origo; /*Left Bottom origo*/ + + lt_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + lb_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + rt_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + rb_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + lv_point_t cir_out; + lv_coord_t tmp_out; + lv_circ_init(&cir_out, &tmp_out, radius); + + lv_point_t cir_in; + lv_coord_t tmp_in; + lv_coord_t radius_in = radius - bwidth; + + if(radius_in < 0) { + radius_in = 0; + } + + lv_circ_init(&cir_in, &tmp_in, radius_in); + + lv_area_t circ_area; + lv_coord_t act_w1; + lv_coord_t act_w2; + +#if LV_ANTIALIAS + /*Store some internal states for anti-aliasing*/ + lv_coord_t out_y_seg_start = 0; + lv_coord_t out_y_seg_end = 0; + lv_coord_t out_x_last = radius; + + + lv_coord_t in_y_seg_start = 0; + lv_coord_t in_y_seg_end = 0; + lv_coord_t in_x_last = radius - bwidth; +#endif + + while(cir_out.y <= cir_out.x) { + + /*Calculate the actual width to avoid overwriting pixels*/ + if(cir_in.y < cir_in.x) { + act_w1 = cir_out.x - cir_in.x; + act_w2 = act_w1; + } else { + act_w1 = cir_out.x - cir_out.y; + act_w2 = act_w1 - 1; + } + +#if LV_ANTIALIAS != 0 + /*New step in y on the outter circle*/ + if(out_x_last != cir_out.x) { + out_y_seg_end = cir_out.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + out_x_last = cir_out.x; + out_y_seg_start = out_y_seg_end; + } + + /*New step in y on the inner circle*/ + if(in_x_last != cir_in.x) { + in_y_seg_end = cir_out.y; + lv_coord_t seg_size = in_y_seg_end - in_y_seg_start; + lv_point_t aa_p; + + aa_p.x = in_x_last; + aa_p.y = in_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = opa - antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = lv_draw_aa_get_opa(seg_size, i, opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + /*Be sure the pixels on the middle are not drawn twice*/ + if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) { + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + } + + in_x_last = cir_in.x; + in_y_seg_start = in_y_seg_end; + + } + +#endif + + + /*Draw the octets to the right bottom corner*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + circ_area.x1 = rb_origo.x + LV_CIRC_OCT1_X(cir_out) - act_w2; + circ_area.x2 = rb_origo.x + LV_CIRC_OCT1_X(cir_out); + circ_area.y1 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out); + circ_area.y2 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + + circ_area.x1 = rb_origo.x + LV_CIRC_OCT2_X(cir_out); + circ_area.x2 = rb_origo.x + LV_CIRC_OCT2_X(cir_out); + circ_area.y1 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out) - act_w1; + circ_area.y2 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the left bottom corner*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + circ_area.x1 = lb_origo.x + LV_CIRC_OCT3_X(cir_out); + circ_area.x2 = lb_origo.x + LV_CIRC_OCT3_X(cir_out); + circ_area.y1 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out) - act_w2; + circ_area.y2 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + + circ_area.x1 = lb_origo.x + LV_CIRC_OCT4_X(cir_out); + circ_area.x2 = lb_origo.x + LV_CIRC_OCT4_X(cir_out) + act_w1; + circ_area.y1 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out); + circ_area.y2 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the left top corner*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + if(lb_origo.y + LV_CIRC_OCT4_Y(cir_out) > lt_origo.y + LV_CIRC_OCT5_Y(cir_out)) { + /*Don't draw if the lines are common in the middle*/ + circ_area.x1 = lt_origo.x + LV_CIRC_OCT5_X(cir_out); + circ_area.x2 = lt_origo.x + LV_CIRC_OCT5_X(cir_out) + act_w2; + circ_area.y1 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out); + circ_area.y2 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + circ_area.x1 = lt_origo.x + LV_CIRC_OCT6_X(cir_out); + circ_area.x2 = lt_origo.x + LV_CIRC_OCT6_X(cir_out); + circ_area.y1 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out); + circ_area.y2 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out) + act_w1; + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the right top corner*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + circ_area.x1 = rt_origo.x + LV_CIRC_OCT7_X(cir_out); + circ_area.x2 = rt_origo.x + LV_CIRC_OCT7_X(cir_out); + circ_area.y1 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out); + circ_area.y2 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out) + act_w2; + fill_fp(&circ_area, mask, color, opa); + + /*Don't draw if the lines are common in the middle*/ + if(rb_origo.y + LV_CIRC_OCT1_Y(cir_out) > rt_origo.y + LV_CIRC_OCT8_Y(cir_out)) { + circ_area.x1 = rt_origo.x + LV_CIRC_OCT8_X(cir_out) - act_w1; + circ_area.x2 = rt_origo.x + LV_CIRC_OCT8_X(cir_out); + circ_area.y1 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out); + circ_area.y2 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + } + lv_circ_next(&cir_out, &tmp_out); + + /*The internal circle will be ready faster + * so check it! */ + if(cir_in.y < cir_in.x) { + lv_circ_next(&cir_in, &tmp_in); + } + } + + +#if LV_ANTIALIAS != 0 + + /*Last parts of the outer anti-alias*/ + out_y_seg_end = cir_out.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + /*In some cases the last pixel in the outer middle is not drawn*/ + if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) { + aa_p.x = out_x_last; + aa_p.y = out_x_last; + + lv_opa_t aa_opa = opa >> 1; + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, style->body.border.color, aa_opa); + } + } + + /*Last parts of the inner anti-alias*/ + in_y_seg_end = cir_in.y; + aa_p.x = in_x_last; + aa_p.y = in_y_seg_start; + seg_size = in_y_seg_end - in_y_seg_start; + + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = lv_draw_aa_get_opa(seg_size, i, opa); + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) { + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + } + +#endif + +} + +#if USE_LV_SHADOW && LV_VDB_SIZE + +/** + * Draw a shadow + * @param rect pointer to rectangle object + * @param mask pointer to a mask area (from the design functions) + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + /* If mask is in the middle of cords do not draw shadow*/ + lv_coord_t radius = style->body.radius; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + radius = lv_draw_cont_radius_corr(radius, width, height); + lv_area_t area_tmp; + + /*Check horizontally without radius*/ + lv_area_copy(&area_tmp, coords); + area_tmp.x1 += radius; + area_tmp.x2 -= radius; + if(lv_area_is_in(mask, &area_tmp) != false) return; + + /*Check vertically without radius*/ + lv_area_copy(&area_tmp, coords); + area_tmp.y1 += radius; + area_tmp.y2 -= radius; + if(lv_area_is_in(mask, &area_tmp) != false) return; + + if(style->body.shadow.type == LV_SHADOW_FULL) { + lv_draw_shadow_full(coords, mask, style, opa_scale); + } else if(style->body.shadow.type == LV_SHADOW_BOTTOM) { + lv_draw_shadow_bottom(coords, mask, style, opa_scale); + } +} + +static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + + /* KNOWN ISSUE + * The algorithm calculates the shadow only above the middle point of the radius (speaking about the left top corner). + * It causes an error because it doesn't consider how long the straight edge is which effects the value of bottom of the corner shadow. + * In addition the straight shadow is drawn from the middles point of the radius however + * the ends of the straight parts still should be effected by the corner shadow. + * It also causes an issue in opacity. A smaller radius means smaller average shadow opacity. + * The solution should be to start `line` from `- swidth` and handle if the straight part is short (or zero) and the value is taken from + * the other corner. `col` also should start from `- swidth` + */ + + + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width; + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + radius += LV_ANTIALIAS; + +#if LV_COMPILER_VLA_SUPPORTED + lv_coord_t curve_x[radius + swidth + 1]; /*Stores the 'x' coordinates of a quarter circle.*/ +#else +# if LV_HOR_RES > LV_VER_RES + lv_coord_t curve_x[LV_HOR_RES]; +# else + lv_coord_t curve_x[LV_VER_RES]; +# endif +#endif + memset(curve_x, 0, sizeof(curve_x)); + lv_point_t circ; + lv_coord_t circ_tmp; + lv_circ_init(&circ, &circ_tmp, radius); + while(lv_circ_cont(&circ)) { + curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ); + curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ); + lv_circ_next(&circ, &circ_tmp); + } + int16_t line; + + int16_t filter_width = 2 * swidth + 1; +#if LV_COMPILER_VLA_SUPPORTED + uint32_t line_1d_blur[filter_width]; +#else +# if LV_HOR_RES > LV_VER_RES + uint32_t line_1d_blur[LV_HOR_RES]; +# else + uint32_t line_1d_blur[LV_VER_RES]; +# endif +#endif + /*1D Blur horizontally*/ + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + for(line = 0; line < filter_width; line++) { + line_1d_blur[line] = (uint32_t)((uint32_t)(filter_width - line) * (opa * 2) << SHADOW_OPA_EXTRA_PRECISION) / (filter_width * filter_width); + } + + uint16_t col; +#if LV_COMPILER_VLA_SUPPORTED + lv_opa_t line_2d_blur[radius + swidth + 1]; +#else +# if LV_HOR_RES > LV_VER_RES + lv_opa_t line_2d_blur[LV_HOR_RES]; +# else + lv_opa_t line_2d_blur[LV_VER_RES]; +# endif +#endif + + lv_point_t point_rt; + lv_point_t point_rb; + lv_point_t point_lt; + lv_point_t point_lb; + lv_point_t ofs_rb; + lv_point_t ofs_rt; + lv_point_t ofs_lb; + lv_point_t ofs_lt; + ofs_rb.x = coords->x2 - radius - LV_ANTIALIAS; + ofs_rb.y = coords->y2 - radius - LV_ANTIALIAS; + + ofs_rt.x = coords->x2 - radius - LV_ANTIALIAS; + ofs_rt.y = coords->y1 + radius + LV_ANTIALIAS; + + ofs_lb.x = coords->x1 + radius + LV_ANTIALIAS; + ofs_lb.y = coords->y2 - radius - LV_ANTIALIAS; + + ofs_lt.x = coords->x1 + radius + LV_ANTIALIAS; + ofs_lt.y = coords->y1 + radius + LV_ANTIALIAS; + bool line_ready; + for(line = 0; line <= radius + swidth; line++) { /*Check all rows and make the 1D blur to 2D*/ + line_ready = false; + for(col = 0; col <= radius + swidth; col++) { /*Check all pixels in a 1D blur line (from the origo to last shadow pixel (radius + swidth))*/ + + /*Sum the opacities from the lines above and below this 'row'*/ + int16_t line_rel; + uint32_t px_opa_sum = 0; + for(line_rel = -swidth; line_rel <= swidth; line_rel ++) { + /*Get the relative x position of the 'line_rel' to 'line'*/ + int16_t col_rel; + if(line + line_rel < 0) { /*Below the radius, here is the blur of the edge */ + col_rel = radius - curve_x[line] - col; + } else if(line + line_rel > radius) { /*Above the radius, here won't be more 1D blur*/ + break; + } else { /*Blur from the curve*/ + col_rel = curve_x[line + line_rel] - curve_x[line] - col; + } + + /*Add the value of the 1D blur on 'col_rel' position*/ + if(col_rel < -swidth) { /*Outside of the blurred area. */ + if(line_rel == -swidth) line_ready = true; /*If no data even on the very first line then it wont't be anything else in this line*/ + break; /*Break anyway because only smaller 'col_rel' values will come */ + } else if(col_rel > swidth) px_opa_sum += line_1d_blur[0]; /*Inside the not blurred area*/ + else px_opa_sum += line_1d_blur[swidth - col_rel]; /*On the 1D blur (+ swidth to align to the center)*/ + } + + line_2d_blur[col] = px_opa_sum >> SHADOW_OPA_EXTRA_PRECISION; + if(line_ready) { + col++; /*To make this line to the last one ( drawing will go to '< col')*/ + break; + } + + } + + /*Flush the line*/ + point_rt.x = curve_x[line] + ofs_rt.x + 1; + point_rt.y = ofs_rt.y - line; + + point_rb.x = curve_x[line] + ofs_rb.x + 1; + point_rb.y = ofs_rb.y + line; + + point_lt.x = ofs_lt.x - curve_x[line] - 1; + point_lt.y = ofs_lt.y - line; + + point_lb.x = ofs_lb.x - curve_x[line] - 1; + point_lb.y = ofs_lb.y + line; + + uint16_t d; + for(d = 1; d < col; d++) { + + if(point_lt.x < ofs_lt.x && point_lt.y < ofs_lt.y) { + px_fp(point_lt.x, point_lt.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_lb.x < ofs_lb.x && point_lb.y > ofs_lb.y) { + px_fp(point_lb.x, point_lb.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_rt.x > ofs_rt.x && point_rt.y < ofs_rt.y) { + px_fp(point_rt.x, point_rt.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_rb.x > ofs_rb.x && point_rb.y > ofs_rb.y) { + px_fp(point_rb.x, point_rb.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + point_rb.x++; + point_lb.x--; + + point_rt.x++; + point_lt.x--; + } + + /* Put the first line to the edges too. + * It is not correct because blur should be done below the corner too + * but is is simple, fast and gives a good enough result*/ + if(line == 0) lv_draw_shadow_full_straight(coords, mask, style, line_2d_blur); + } +} + + +static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + radius += LV_ANTIALIAS * SHADOW_BOTTOM_AA_EXTRA_RADIUS; + swidth += LV_ANTIALIAS; +#if LV_COMPILER_VLA_SUPPORTED + lv_coord_t curve_x[radius + 1]; /*Stores the 'x' coordinates of a quarter circle.*/ +#else +# if LV_HOR_RES > LV_VER_RES + lv_coord_t curve_x[LV_HOR_RES]; +# else + lv_coord_t curve_x[LV_VER_RES]; +# endif +#endif + lv_point_t circ; + lv_coord_t circ_tmp; + lv_circ_init(&circ, &circ_tmp, radius); + while(lv_circ_cont(&circ)) { + curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ); + curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ); + lv_circ_next(&circ, &circ_tmp); + } + + int16_t col; +#if LV_COMPILER_VLA_SUPPORTED + lv_opa_t line_1d_blur[swidth]; +#else +# if LV_HOR_RES > LV_VER_RES + lv_opa_t line_1d_blur[LV_HOR_RES]; +# else + lv_opa_t line_1d_blur[LV_VER_RES]; +# endif +#endif + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + for(col = 0; col < swidth; col++) { + line_1d_blur[col] = (uint32_t)((uint32_t)(swidth - col) * opa / 2) / (swidth); + } + + lv_point_t point_l; + lv_point_t point_r; + lv_area_t area_mid; + lv_point_t ofs_l; + lv_point_t ofs_r; + + ofs_l.x = coords->x1 + radius; + ofs_l.y = coords->y2 - radius + 1 - LV_ANTIALIAS; + + ofs_r.x = coords->x2 - radius; + ofs_r.y = coords->y2 - radius + 1 - LV_ANTIALIAS; + + for(col = 0; col <= radius; col++) { + point_l.x = ofs_l.x - col ; + point_l.y = ofs_l.y + curve_x[col]; + + point_r.x = ofs_r.x + col; + point_r.y = ofs_r.y + curve_x[col]; + + lv_opa_t px_opa; + int16_t diff = col == 0 ? 0 : curve_x[col - 1] - curve_x[col]; + uint16_t d; + for(d = 0; d < swidth; d++) { + /*When stepping a pixel in y calculate the average with the pixel from the prev. column to make a blur */ + if(diff == 0) { + px_opa = line_1d_blur[d]; + } else { + px_opa = (uint16_t)((uint16_t)line_1d_blur[d] + line_1d_blur[d - diff]) >> 1; + } + px_fp(point_l.x, point_l.y, mask, style->body.shadow.color, px_opa); + point_l.y ++; + + /*Don't overdraw the pixel on the middle*/ + if(point_r.x > ofs_l.x) { + px_fp(point_r.x, point_r.y, mask, style->body.shadow.color, px_opa); + } + point_r.y ++; + } + + } + + area_mid.x1 = ofs_l.x + 1; + area_mid.y1 = ofs_l.y + radius; + area_mid.x2 = ofs_r.x - 1; + area_mid.y2 = area_mid.y1; + + uint16_t d; + for(d = 0; d < swidth; d++) { + fill_fp(&area_mid, mask, style->body.shadow.color, line_1d_blur[d]); + area_mid.y1 ++; + area_mid.y2 ++; + } +} + +static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map) +{ + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width;// + LV_ANTIALIAS; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + radius += LV_ANTIALIAS; + + lv_area_t right_area; + right_area.x1 = coords->x2 + 1 - LV_ANTIALIAS; + right_area.y1 = coords->y1 + radius + LV_ANTIALIAS; + right_area.x2 = right_area.x1; + right_area.y2 = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t left_area; + left_area.x1 = coords->x1 - 1 + LV_ANTIALIAS; + left_area.y1 = coords->y1 + radius + LV_ANTIALIAS; + left_area.x2 = left_area.x1; + left_area.y2 = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t top_area; + top_area.x1 = coords->x1 + radius + LV_ANTIALIAS; + top_area.y1 = coords->y1 - 1 + LV_ANTIALIAS; + top_area.x2 = coords->x2 - radius - LV_ANTIALIAS; + top_area.y2 = top_area.y1; + + lv_area_t bottom_area; + bottom_area.x1 = coords->x1 + radius + LV_ANTIALIAS; + bottom_area.y1 = coords->y2 + 1 - LV_ANTIALIAS; + bottom_area.x2 = coords->x2 - radius - LV_ANTIALIAS; + bottom_area.y2 = bottom_area.y1; + + lv_opa_t opa_act; + int16_t d; + for(d = 1 /*+ LV_ANTIALIAS*/; d <= swidth/* - LV_ANTIALIAS*/; d++) { + opa_act = map[d]; + + fill_fp(&right_area, mask, style->body.shadow.color, opa_act); + right_area.x1++; + right_area.x2++; + + fill_fp(&left_area, mask, style->body.shadow.color, opa_act); + left_area.x1--; + left_area.x2--; + + fill_fp(&top_area, mask, style->body.shadow.color, opa_act); + top_area.y1--; + top_area.y2--; + + fill_fp(&bottom_area, mask, style->body.shadow.color, opa_act); + bottom_area.y1++; + bottom_area.y2++; + } +} + +#endif + + +static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h) +{ + if(r >= (w >> 1)) { + r = (w >> 1); + if(r != 0) r--; + } + if(r >= (h >> 1)) { + r = (h >> 1); + if(r != 0) r--; + } + + if(r > 0) r -= LV_ANTIALIAS; + + return r; +} + +#if LV_ANTIALIAS + +/** + * Approximate the opacity for anti-aliasing. + * Used the first segment of a circle which is the longest and have the most non-linearity (cos) + * @param seg length of the line segment + * @param px_id index of pixel on the line segment + * @param line_opa opacity of the lien (it will be the max opacity) + * @return the desired opacity of the pixel + */ +static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa) +{ + static const lv_opa_t opa_map[8] = {250, 242, 221, 196, 163, 122, 74, 18}; + + if(seg == 0) return LV_OPA_TRANSP; + else if(seg == 1) return LV_OPA_80; + else { + + uint8_t id = (uint32_t)((uint32_t)px_id * (sizeof(opa_map) - 1)) / (seg - 1); + return (uint32_t)((uint32_t) opa_map[id] * opa) >> 8; + + } + +} + +#endif diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_rect.h b/bdk/libs/lvgl/lv_draw/lv_draw_rect.h new file mode 100644 index 0000000..933590c --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_rect.h @@ -0,0 +1,48 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c new file mode 100644 index 0000000..84c9d3f --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c @@ -0,0 +1,168 @@ +/** + * @file lv_draw_triangle.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_triangle.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static void point_swap(lv_point_t * p1, lv_point_t * p2); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color) +{ + lv_point_t tri[3]; + + memcpy(tri, points, sizeof(tri)); + + /*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/ + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]); + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + + /*Return is the triangle is degenerated*/ + if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return; + if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return; + if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return; + + if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return; + if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return; + + /*Draw the triangle*/ + lv_point_t edge1; + lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x); + lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1; + lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y); + lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1; + lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + lv_coord_t err_tmp1; + + lv_point_t edge2; + lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x); + lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1; + lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y); + lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1; + lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2; + lv_coord_t err_tmp2; + + lv_coord_t y1_tmp; + lv_coord_t y2_tmp; + + edge1.x = tri[0].x; + edge1.y = tri[0].y; + edge2.x = tri[0].x; + edge2.y = tri[0].y; + lv_area_t act_area; + lv_area_t draw_area; + + while(1) { + act_area.x1 = edge1.x; + act_area.x2 = edge2.x ; + act_area.y1 = edge1.y; + act_area.y2 = edge2.y ; + + + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/ + fill_fp(&draw_area, mask, color, LV_OPA_50); + + /*Calc. the next point of edge1*/ + y1_tmp = edge1.y; + do { + if(edge1.x == tri[1].x && edge1.y == tri[1].y) { + + dx1 = LV_MATH_ABS(tri[1].x - tri[2].x); + sx1 = tri[1].x < tri[2].x ? 1 : -1; + dy1 = LV_MATH_ABS(tri[1].y - tri[2].y); + sy1 = tri[1].y < tri[2].y ? 1 : -1; + err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + } else if(edge1.x == tri[2].x && edge1.y == tri[2].y) return; + err_tmp1 = err1; + if(err_tmp1 > -dx1) { + err1 -= dy1; + edge1.x += sx1; + } + if(err_tmp1 < dy1) { + err1 += dx1; + edge1.y += sy1; + } + } while(edge1.y == y1_tmp); + + /*Calc. the next point of edge2*/ + y2_tmp = edge2.y; + do { + if(edge2.x == tri[2].x && edge2.y == tri[2].y) return; + err_tmp2 = err2; + if(err_tmp2 > -dx2) { + err2 -= dy2; + edge2.x += sx2; + } + if(err_tmp2 < dy2) { + err2 += dx2; + edge2.y += sy2; + } + } while(edge2.y == y2_tmp); + } +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + + +#if USE_LV_TRIANGLE != 0 +/** + * Swap two points + * p1 pointer to the first point + * p2 pointer to the second point + */ +static void point_swap(lv_point_t * p1, lv_point_t * p2) +{ + lv_point_t tmp; + tmp.x = p1->x; + tmp.y = p1->y; + + p1->x = p2->x; + p1->y = p2->y; + + p2->x = tmp.x; + p2->y = tmp.y; + +} + +#endif diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h new file mode 100644 index 0000000..c3c6208 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c new file mode 100644 index 0000000..ebe5f57 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c @@ -0,0 +1,691 @@ +/** + * @file lv_vdraw.c + * + */ + +#include "lv_draw_vbasic.h" + +#include +#include + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_log.h" + +#if LV_VDB_SIZE != 0 + +#include +#include "../lv_core/lv_vdb.h" +#include "lv_draw.h" + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ +#define VFILL_HW_ACC_SIZE_LIMIT 50 /*Always fill < 50 px with 'sw_color_fill' because of the hw. init overhead*/ + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); +static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa); + +#if LV_COLOR_SCREEN_TRANSP +static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Put a pixel in the Virtual Display Buffer + * @param x pixel x coordinate + * @param y pixel y coordinate + * @param mask_p fill only on this mask (truncated to VDB area) + * @param color pixel color + * @param opa opacity of the area (0..255) + */ +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa) +{ + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Pixel out of the mask*/ + if(x < mask_p->x1 || x > mask_p->x2 || + y < mask_p->y1 || y > mask_p->y2) { + return; + } + + uint32_t vdb_width = lv_area_get_width(&vdb_p->area); + + /*Make the coordinates relative to VDB*/ + x -= vdb_p->area.x1; + y -= vdb_p->area.y1; + + lv_disp_t * disp = lv_disp_get_active(); + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, x, y, color, opa); + } else { + lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x; +#if LV_COLOR_SCREEN_TRANSP == 0 + if(opa == LV_OPA_COVER) { + *vdb_px_p = color; + } else { + *vdb_px_p = lv_color_mix(color, *vdb_px_p, opa); + } +#else + *vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).alpha, color, opa); +#endif + } +} + + +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask (truncated to VDB area) + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa) +{ + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_area_t res_a; + bool union_ok; + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Get the union of cord and mask*/ + /* The mask is already truncated to the vdb size + * in 'lv_refr_area_with_vdb' function */ + union_ok = lv_area_intersect(&res_a, cords_p, mask_p); + + /*If there are common part of the three area then draw to the vdb*/ + if(union_ok == false) return; + + lv_area_t vdb_rel_a; /*Stores relative coordinates on vdb*/ + vdb_rel_a.x1 = res_a.x1 - vdb_p->area.x1; + vdb_rel_a.y1 = res_a.y1 - vdb_p->area.y1; + vdb_rel_a.x2 = res_a.x2 - vdb_p->area.x1; + vdb_rel_a.y2 = res_a.y2 - vdb_p->area.y1; + + lv_color_t * vdb_buf_tmp = vdb_p->buf; + uint32_t vdb_width = lv_area_get_width(&vdb_p->area); + /*Move the vdb_tmp to the first row*/ + vdb_buf_tmp += vdb_width * vdb_rel_a.y1; + + +#if USE_LV_GPU + static LV_ATTRIBUTE_MEM_ALIGN lv_color_t color_array_tmp[LV_HOR_RES]; /*Used by 'lv_disp_mem_blend'*/ + static lv_coord_t last_width = -1; + + lv_coord_t w = lv_area_get_width(&vdb_rel_a); + /*Don't use hw. acc. for every small fill (because of the init overhead)*/ + if(w < VFILL_HW_ACC_SIZE_LIMIT) { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + /*Not opaque fill*/ + else if(opa == LV_OPA_COVER) { + /*Use hw fill if present*/ + if(lv_disp_is_mem_fill_supported()) { + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_fill(&vdb_buf_tmp[vdb_rel_a.x1], w, color); + vdb_buf_tmp += vdb_width; + } + } + /*Use hw blend if present and the area is not too small*/ + else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT && + lv_disp_is_mem_blend_supported()) { + /*Fill a one line sized buffer with a color and blend this later*/ + if(color_array_tmp[0].full != color.full || last_width != w) { + uint16_t i; + for(i = 0; i < w; i++) { + color_array_tmp[i].full = color.full; + } + last_width = w; + } + + /*Blend the filled line to every line VDB line-by-line*/ + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa); + vdb_buf_tmp += vdb_width; + } + + } + /*Else use sw fill if no better option*/ + else { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + + } + /*Fill with opacity*/ + else { + /*Use hw blend if present*/ + if(lv_disp_is_mem_blend_supported()) { + if(color_array_tmp[0].full != color.full || last_width != w) { + uint16_t i; + for(i = 0; i < w; i++) { + color_array_tmp[i].full = color.full; + } + + last_width = w; + } + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa); + vdb_buf_tmp += vdb_width; + } + + } + /*Use sw fill with opa if no better option*/ + else { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + + } +#else + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); +#endif +} + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area (truncated to VDB area) + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa) +{ + const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + if(font_p == NULL) { + LV_LOG_WARN("Font: character's bitmap not found"); + return; + } + + lv_coord_t pos_x = pos_p->x; + lv_coord_t pos_y = pos_p->y; + uint8_t letter_w = lv_font_get_real_width(font_p, letter); + uint8_t letter_h = lv_font_get_height(font_p); + uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/ + const uint8_t * bpp_opa_table; + uint8_t mask_init; + uint8_t mask; + + if(lv_font_is_monospace(font_p, letter)) { + pos_x += (lv_font_get_width(font_p, letter) - letter_w) / 2; + } + + + switch(bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + mask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + mask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + mask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + mask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + return; /*Invalid bpp. Can't render the letter*/ + } + + const uint8_t * map_p = lv_font_get_bitmap(font_p, letter); + + if(map_p == NULL) return; + + /*If the letter is completely out of mask don't draw it */ + if(pos_x + letter_w < mask_p->x1 || pos_x > mask_p->x2 || + pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return; + + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area); + lv_color_t * vdb_buf_tmp = vdb_p->buf; + lv_coord_t col, row; + uint8_t col_bit; + uint8_t col_byte_cnt; + uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(letter_w & 0x7) width_byte_scr++; + uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/ + if((letter_w * bpp) & 0x7) width_byte_bpp++; + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x; + lv_coord_t col_end = pos_x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_x + 1; + lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y; + lv_coord_t row_end = pos_y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_y + 1; + + /*Set a pointer on VDB to the first pixel of the letter*/ + vdb_buf_tmp += ((pos_y - vdb_p->area.y1) * vdb_width) + + pos_x - vdb_p->area.x1; + + /*If the letter is partially out of mask the move there on VDB*/ + vdb_buf_tmp += (row_start * vdb_width) + col_start; + + /*Move on the map too*/ + map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3); + + lv_disp_t * disp = lv_disp_get_active(); + + uint8_t letter_px; + lv_opa_t px_opa; + for(row = row_start; row < row_end; row ++) { + col_byte_cnt = 0; + col_bit = (col_start * bpp) % 8; + mask = mask_init >> col_bit; + for(col = col_start; col < col_end; col ++) { + letter_px = (*map_p & mask) >> (8 - col_bit - bpp); + if(letter_px != 0) { + if(opa == LV_OPA_COVER) { + px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px]; + } else { + px_opa = bpp == 8 ? + (uint16_t)((uint16_t)letter_px * opa) >> 8 : + (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; + } + + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, + (col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->area.y1, + color, px_opa); + } else { +#if LV_COLOR_SCREEN_TRANSP == 0 + *vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa); +#else + *vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa); +#endif + } + } + + vdb_buf_tmp++; + + if(col_bit < 8 - bpp) { + col_bit += bpp; + mask = mask >> bpp; + } else { + col_bit = 0; + col_byte_cnt ++; + mask = mask_init; + map_p ++; + } + } + + map_p += (width_byte_bpp) - col_byte_cnt; + vdb_buf_tmp += vdb_width - (col_end - col_start); /*Next row in VDB*/ + } +} + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) +{ + + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_area_t masked_a; + bool union_ok; + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Get the union of map size and mask*/ + /* The mask is already truncated to the vdb size + * in 'lv_refr_area_with_vdb' function */ + union_ok = lv_area_intersect(&masked_a, cords_p, mask_p); + + /*If there are common part of the three area then draw to the vdb*/ + if(union_ok == false) return; + + /*The pixel size in byte is different if an alpha byte is added too*/ + uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t); + + /*If the map starts OUT of the masked area then calc. the first pixel*/ + lv_coord_t map_width = lv_area_get_width(cords_p); + if(cords_p->y1 < masked_a.y1) { + map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1)) * px_size_byte; + } + if(cords_p->x1 < masked_a.x1) { + map_p += (masked_a.x1 - cords_p->x1) * px_size_byte; + } + + /*Stores coordinates relative to the current VDB*/ + masked_a.x1 = masked_a.x1 - vdb_p->area.x1; + masked_a.y1 = masked_a.y1 - vdb_p->area.y1; + masked_a.x2 = masked_a.x2 - vdb_p->area.x1; + masked_a.y2 = masked_a.y2 - vdb_p->area.y1; + + lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area); + lv_color_t * vdb_buf_tmp = vdb_p->buf; + vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/ + vdb_buf_tmp += (uint32_t) masked_a.x1; /*Move to the first col*/ + + lv_coord_t row; + lv_coord_t map_useful_w = lv_area_get_width(&masked_a); + + lv_disp_t * disp = lv_disp_get_active(); + + /*The simplest case just copy the pixels into the VDB*/ + if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) { + + /*Use the custom VDB write function is exists*/ + if(disp->driver.vdb_wr) { + lv_coord_t col; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = 0; col < map_useful_w; col++) { + lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]); + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa); + } + map_p += map_width * px_size_byte; /*Next row on the map*/ + } + } + /*Normal native VDB*/ + else { + for(row = masked_a.y1; row <= masked_a.y2; row++) { +#if USE_LV_GPU + if(lv_disp_is_mem_blend_supported() == false) { + sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); + } else { + lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); + } +#else + sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); +#endif + map_p += map_width * px_size_byte; /*Next row on the map*/ + vdb_buf_tmp += vdb_width; /*Next row on the VDB*/ + } + } + } + + /*In the other cases every pixel need to be checked one-by-one*/ + else { + lv_color_t chroma_key_color = LV_COLOR_TRANSP; + lv_coord_t col; + lv_color_t last_img_px = LV_COLOR_BLACK; + lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa); + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = 0; col < map_useful_w; col++) { + lv_opa_t opa_result = opa; + uint8_t * px_color_p = (uint8_t *) &map_p[(uint32_t)col * px_size_byte]; + lv_color_t px_color; + + /*Calculate with the pixel level alpha*/ + if(alpha_byte) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + px_color.full = px_color_p[0]; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + px_color.full = px_color_p[0] + (px_color_p[1] << 8); +#elif LV_COLOR_DEPTH == 32 + px_color = *((lv_color_t *)px_color_p); +#endif + lv_opa_t px_opa = *(px_color_p + LV_IMG_PX_SIZE_ALPHA_BYTE - 1); + if(px_opa == LV_OPA_TRANSP) continue; + else if(px_opa != LV_OPA_COVER) opa_result = (uint32_t)((uint32_t)px_opa * opa_result) >> 8; + } else { + px_color = *((lv_color_t *)px_color_p); + } + + /*Handle chroma key*/ + if(chroma_key && px_color.full == chroma_key_color.full) continue; + + /*Re-color the pixel if required*/ + if(recolor_opa != LV_OPA_TRANSP) { + if(last_img_px.full != px_color.full) { /*Minor acceleration: calculate only for new colors (save the last)*/ + last_img_px = px_color; + recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa); + } + /*Handle custom VDB write is present*/ + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, recolored_px, opa_result); + } + /*Normal native VDB write*/ + else { + if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full; + else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result); + } + } else { + /*Handle custom VDB write is present*/ + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa_result); + } + /*Normal native VDB write*/ + else { + if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color; + else { +#if LV_COLOR_SCREEN_TRANSP == 0 + vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result); +#else + vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].alpha, px_color, opa_result); +#endif + } + } + } + } + + map_p += map_width * px_size_byte; /*Next row on the map*/ + vdb_buf_tmp += vdb_width; /*Next row on the VDB*/ + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Blend pixels to destination memory using opacity + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa) +{ + if(opa == LV_OPA_COVER) { + memcpy(dest, src, length * sizeof(lv_color_t)); + } else { + uint32_t col; + for(col = 0; col < length; col++) { + dest[col] = lv_color_mix(src[col], dest[col], opa); + } + } +} + +/** + * + * @param mem_area coordinates of 'mem' memory area + * @param mem a memory address. Considered to a rectangular window according to 'mem_area' + * @param fill_area coordinates of an area to fill. Relative to 'mem_area'. + * @param color fill color + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa) +{ + /*Set all row in vdb to the given color*/ + lv_coord_t row; + lv_coord_t col; + lv_coord_t mem_width = lv_area_get_width(mem_area); + + lv_disp_t * disp = lv_disp_get_active(); + if(disp->driver.vdb_wr) { + for(col = fill_area->x1; col <= fill_area->x2; col++) { + for(row = fill_area->y1; row <= fill_area->y2; row++) { + disp->driver.vdb_wr((uint8_t *)mem, mem_width, col, row, color, opa); + } + } + } else { + mem += fill_area->y1 * mem_width; /*Go to the first row*/ + + /*Run simpler function without opacity*/ + if(opa == LV_OPA_COVER) { + + /*Fill the first row with 'color'*/ + for(col = fill_area->x1; col <= fill_area->x2; col++) { + mem[col] = color; + } + + /*Copy the first row to all other rows*/ + lv_color_t * mem_first = &mem[fill_area->x1]; + lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t); + mem += mem_width; + + for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) { + memcpy(&mem[fill_area->x1], mem_first, copy_size); + mem += mem_width; + } + } + /*Calculate with alpha too*/ + else { + +#if LV_COLOR_SCREEN_TRANSP == 0 + lv_color_t bg_tmp = LV_COLOR_BLACK; + lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa); +#endif + for(row = fill_area->y1; row <= fill_area->y2; row++) { + for(col = fill_area->x1; col <= fill_area->x2; col++) { +#if LV_COLOR_SCREEN_TRANSP == 0 + /*If the bg color changed recalculate the result color*/ + if(mem[col].full != bg_tmp.full) { + bg_tmp = mem[col]; + opa_tmp = lv_color_mix(color, bg_tmp, opa); + } + + mem[col] = opa_tmp; + +#else + mem[col] = color_mix_2_alpha(mem[col], mem[col].alpha, color, opa); +#endif + } + mem += mem_width; + } + } + } +} + +#if LV_COLOR_SCREEN_TRANSP + +/** + * Mix two colors. Both color can have alpha value. It requires ARGB888 colors. + * @param bg_color background color + * @param bg_opa alpha of the background color + * @param fg_color foreground color + * @param fg_opa alpha of the foreground color + * @return the mixed color. the alpha channel (color.alpha) contains the result alpha + */ +static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa) +{ + /* Pick the foreground if it's fully opaque or the Background is fully transparent*/ + if(fg_opa == LV_OPA_COVER && bg_opa <= LV_OPA_MIN) { + fg_color.alpha = fg_opa; + return fg_color; + } + /*Transparent foreground: use the Background*/ + else if(fg_opa <= LV_OPA_MIN) { + return bg_color; + } + /*Opaque background: use simple mix*/ + else if(bg_opa >= LV_OPA_MAX) { + return lv_color_mix(fg_color, bg_color, fg_opa); + } + /*Both colors have alpha. Expensive calculation need to be applied*/ + else { + /*Save the parameters and the result. If they will be asked again don't compute again*/ + static lv_opa_t fg_opa_save = 0; + static lv_opa_t bg_opa_save = 0; + static lv_color_t c = {{0}}; + + if(fg_opa != fg_opa_save || bg_opa != bg_opa_save) { + fg_opa_save = fg_opa; + bg_opa_save = bg_opa; + /*Info: https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/ + lv_opa_t alpha_res = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8); + if(alpha_res == 0) { + while(1); + } + lv_opa_t ratio = (uint16_t)((uint16_t) fg_opa * 255) / alpha_res; + c = lv_color_mix(fg_color, bg_color, ratio); + c.alpha = alpha_res; + } + return c; + + } +} +#endif /*LV_COLOR_SCREEN_TRANSP*/ + +#endif diff --git a/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h new file mode 100644 index 0000000..88838b7 --- /dev/null +++ b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h @@ -0,0 +1,89 @@ +/** + * @file lv_draw_vbasic.h + * + */ + +#ifndef LV_DRAW_VBASIC_H +#define LV_DRAW_VBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +#endif /*LV_VDB_SIZE != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c new file mode 100644 index 0000000..c97eda6 --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c @@ -0,0 +1,58 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_120 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols-huge.ttf 120 px Font in U+f002 () .. U+f007 () range with all bpp + * Sparse font with only these characters:  +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_120_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_120 == 8 + {.w_px = 103, .glyph_index = 0}, /*Unicode: U+f002 ()*/ + {.w_px = 103, .glyph_index = 12360}, /*Unicode: U+f003 ()*/ + {.w_px = 103, .glyph_index = 24720}, /*Unicode: U+f005 ()*/ + {.w_px = 103, .glyph_index = 37080}, /*Unicode: U+f007 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_120 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 120, /*Font height in pixels*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x36E00), /*Bitmap of glyphs*/ + .glyph_dsc = hekate_symbol_120_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 4, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_120 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_100*/ diff --git a/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c new file mode 100644 index 0000000..426bde8 --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c @@ -0,0 +1,159 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_20 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols.ttf 20 px Font in U+f000 () .. U+f2ee () range with all bpp + * Sparse font with only these characters:  +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_20_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_20 == 4 + {.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 ()*/ + {.w_px = 16, .glyph_index = 60}, /*Unicode: U+f008 ()*/ + {.w_px = 20, .glyph_index = 220}, /*Unicode: U+f00b ()*/ + {.w_px = 22, .glyph_index = 420}, /*Unicode: U+f00c ()*/ + {.w_px = 16, .glyph_index = 640}, /*Unicode: U+f00d ()*/ + {.w_px = 18, .glyph_index = 800}, /*Unicode: U+f011 ()*/ + {.w_px = 18, .glyph_index = 980}, /*Unicode: U+f013 ()*/ + {.w_px = 16, .glyph_index = 1160}, /*Unicode: U+f014 ()*/ + {.w_px = 23, .glyph_index = 1320}, /*Unicode: U+f015 ()*/ + {.w_px = 18, .glyph_index = 1560}, /*Unicode: U+f019 ()*/ + {.w_px = 23, .glyph_index = 1740}, /*Unicode: U+f01c ()*/ + {.w_px = 18, .glyph_index = 1980}, /*Unicode: U+f021 ()*/ + {.w_px = 18, .glyph_index = 2160}, /*Unicode: U+f026 ()*/ + {.w_px = 18, .glyph_index = 2340}, /*Unicode: U+f027 ()*/ + {.w_px = 13, .glyph_index = 2520}, /*Unicode: U+f028 ()*/ + {.w_px = 13, .glyph_index = 2660}, /*Unicode: U+f03e ()*/ + {.w_px = 16, .glyph_index = 2800}, /*Unicode: U+f040 ()*/ + {.w_px = 13, .glyph_index = 2960}, /*Unicode: U+f048 ()*/ + {.w_px = 13, .glyph_index = 3100}, /*Unicode: U+f04b ()*/ + {.w_px = 13, .glyph_index = 3240}, /*Unicode: U+f04c ()*/ + {.w_px = 9, .glyph_index = 3380}, /*Unicode: U+f04d ()*/ + {.w_px = 23, .glyph_index = 3480}, /*Unicode: U+f051 ()*/ + {.w_px = 21, .glyph_index = 3720}, /*Unicode: U+f052 ()*/ + {.w_px = 11, .glyph_index = 3940}, /*Unicode: U+f053 ()*/ + {.w_px = 11, .glyph_index = 4060}, /*Unicode: U+f054 ()*/ + {.w_px = 18, .glyph_index = 4180}, /*Unicode: U+f067 ()*/ + {.w_px = 18, .glyph_index = 4360}, /*Unicode: U+f068 ()*/ + {.w_px = 20, .glyph_index = 4540}, /*Unicode: U+f071 ()*/ + {.w_px = 20, .glyph_index = 4740}, /*Unicode: U+f074 ()*/ + {.w_px = 18, .glyph_index = 4940}, /*Unicode: U+f077 ()*/ + {.w_px = 18, .glyph_index = 5120}, /*Unicode: U+f078 ()*/ + {.w_px = 18, .glyph_index = 5300}, /*Unicode: U+f079 ()*/ + {.w_px = 20, .glyph_index = 5480}, /*Unicode: U+f07b ()*/ + {.w_px = 18, .glyph_index = 5680}, /*Unicode: U+f093 ()*/ + {.w_px = 25, .glyph_index = 5860}, /*Unicode: U+f095 ()*/ + {.w_px = 18, .glyph_index = 6120}, /*Unicode: U+f0c4 ()*/ + {.w_px = 16, .glyph_index = 6300}, /*Unicode: U+f0c5 ()*/ + {.w_px = 17, .glyph_index = 6460}, /*Unicode: U+f0c7 ()*/ + {.w_px = 8, .glyph_index = 6640}, /*Unicode: U+f0e7 ()*/ + {.w_px = 12, .glyph_index = 6720}, /*Unicode: U+f0f3 ()*/ + {.w_px = 23, .glyph_index = 6840}, /*Unicode: U+f11c ()*/ + {.w_px = 18, .glyph_index = 7080}, /*Unicode: U+f124 ()*/ + {.w_px = 13, .glyph_index = 7260}, /*Unicode: U+f15b ()*/ + {.w_px = 20, .glyph_index = 7400}, /*Unicode: U+f1eb ()*/ + {.w_px = 26, .glyph_index = 7600}, /*Unicode: U+f240 ()*/ + {.w_px = 26, .glyph_index = 7860}, /*Unicode: U+f241 ()*/ + {.w_px = 26, .glyph_index = 8120}, /*Unicode: U+f242 ()*/ + {.w_px = 26, .glyph_index = 8380}, /*Unicode: U+f243 ()*/ + {.w_px = 26, .glyph_index = 8640}, /*Unicode: U+f244 ()*/ + {.w_px = 20, .glyph_index = 8900}, /*Unicode: U+f293 ()*/ + +#elif USE_HEKATE_SYMBOL_20 == 8 + {.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 ()*/ + {.w_px = 16, .glyph_index = 100}, /*Unicode: U+f008 ()*/ + {.w_px = 20, .glyph_index = 420}, /*Unicode: U+f00b ()*/ + {.w_px = 22, .glyph_index = 820}, /*Unicode: U+f00c ()*/ + {.w_px = 16, .glyph_index = 1260}, /*Unicode: U+f00d ()*/ + {.w_px = 18, .glyph_index = 1580}, /*Unicode: U+f011 ()*/ + {.w_px = 18, .glyph_index = 1940}, /*Unicode: U+f013 ()*/ + {.w_px = 16, .glyph_index = 2300}, /*Unicode: U+f014 ()*/ + {.w_px = 23, .glyph_index = 2620}, /*Unicode: U+f015 ()*/ + {.w_px = 18, .glyph_index = 3080}, /*Unicode: U+f019 ()*/ + {.w_px = 23, .glyph_index = 3440}, /*Unicode: U+f01c ()*/ + {.w_px = 18, .glyph_index = 3900}, /*Unicode: U+f021 ()*/ + {.w_px = 18, .glyph_index = 4260}, /*Unicode: U+f026 ()*/ + {.w_px = 18, .glyph_index = 4620}, /*Unicode: U+f027 ()*/ + {.w_px = 13, .glyph_index = 4980}, /*Unicode: U+f028 ()*/ + {.w_px = 13, .glyph_index = 5240}, /*Unicode: U+f03e ()*/ + {.w_px = 16, .glyph_index = 5500}, /*Unicode: U+f040 ()*/ + {.w_px = 13, .glyph_index = 5820}, /*Unicode: U+f048 ()*/ + {.w_px = 13, .glyph_index = 6080}, /*Unicode: U+f04b ()*/ + {.w_px = 13, .glyph_index = 6340}, /*Unicode: U+f04c ()*/ + {.w_px = 9, .glyph_index = 6600}, /*Unicode: U+f04d ()*/ + {.w_px = 23, .glyph_index = 6780}, /*Unicode: U+f051 ()*/ + {.w_px = 21, .glyph_index = 7240}, /*Unicode: U+f052 ()*/ + {.w_px = 11, .glyph_index = 7660}, /*Unicode: U+f053 ()*/ + {.w_px = 11, .glyph_index = 7880}, /*Unicode: U+f054 ()*/ + {.w_px = 18, .glyph_index = 8100}, /*Unicode: U+f067 ()*/ + {.w_px = 18, .glyph_index = 8460}, /*Unicode: U+f068 ()*/ + {.w_px = 20, .glyph_index = 8820}, /*Unicode: U+f071 ()*/ + {.w_px = 20, .glyph_index = 9220}, /*Unicode: U+f074 ()*/ + {.w_px = 18, .glyph_index = 9620}, /*Unicode: U+f077 ()*/ + {.w_px = 18, .glyph_index = 9980}, /*Unicode: U+f078 ()*/ + {.w_px = 18, .glyph_index = 10340}, /*Unicode: U+f079 ()*/ + {.w_px = 20, .glyph_index = 10700}, /*Unicode: U+f07b ()*/ + {.w_px = 18, .glyph_index = 11100}, /*Unicode: U+f093 ()*/ + {.w_px = 25, .glyph_index = 11460}, /*Unicode: U+f095 ()*/ + {.w_px = 18, .glyph_index = 11960}, /*Unicode: U+f0c4 ()*/ + {.w_px = 16, .glyph_index = 12320}, /*Unicode: U+f0c5 ()*/ + {.w_px = 17, .glyph_index = 12640}, /*Unicode: U+f0c7 ()*/ + {.w_px = 8, .glyph_index = 12980}, /*Unicode: U+f0e7 ()*/ + {.w_px = 12, .glyph_index = 13140}, /*Unicode: U+f0f3 ()*/ + {.w_px = 23, .glyph_index = 13380}, /*Unicode: U+f11c ()*/ + {.w_px = 18, .glyph_index = 13840}, /*Unicode: U+f124 ()*/ + {.w_px = 13, .glyph_index = 14200}, /*Unicode: U+f15b ()*/ + {.w_px = 20, .glyph_index = 14460}, /*Unicode: U+f1eb ()*/ + {.w_px = 26, .glyph_index = 14860}, /*Unicode: U+f240 ()*/ + {.w_px = 26, .glyph_index = 15380}, /*Unicode: U+f241 ()*/ + {.w_px = 26, .glyph_index = 15900}, /*Unicode: U+f242 ()*/ + {.w_px = 26, .glyph_index = 16420}, /*Unicode: U+f243 ()*/ + {.w_px = 26, .glyph_index = 16940}, /*Unicode: U+f244 ()*/ + {.w_px = 20, .glyph_index = 17460}, /*Unicode: U+f293 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_20 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = hekate_symbol_20_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0xFC00), + .glyph_dsc = hekate_symbol_20_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 50, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_20 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_HEKATE_SYMBOL_20 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_20*/ diff --git a/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c new file mode 100644 index 0000000..4e0da47 --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c @@ -0,0 +1,159 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_30 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols.ttf 30 px Font in U+f000 () .. U+f2ee () range with all bpp + * Sparse font with only these characters:  +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_30_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_30 == 4 + {.w_px = 7, .glyph_index = 0}, /*Unicode: U+f001 ()*/ + {.w_px = 25, .glyph_index = 120}, /*Unicode: U+f008 ()*/ + {.w_px = 27, .glyph_index = 510}, /*Unicode: U+f00b ()*/ + {.w_px = 31, .glyph_index = 930}, /*Unicode: U+f00c ()*/ + {.w_px = 22, .glyph_index = 1410}, /*Unicode: U+f00d ()*/ + {.w_px = 25, .glyph_index = 1740}, /*Unicode: U+f011 ()*/ + {.w_px = 25, .glyph_index = 2130}, /*Unicode: U+f013 ()*/ + {.w_px = 23, .glyph_index = 2520}, /*Unicode: U+f014 ()*/ + {.w_px = 34, .glyph_index = 2880}, /*Unicode: U+f015 ()*/ + {.w_px = 25, .glyph_index = 3390}, /*Unicode: U+f019 ()*/ + {.w_px = 32, .glyph_index = 3780}, /*Unicode: U+f01c ()*/ + {.w_px = 25, .glyph_index = 4260}, /*Unicode: U+f021 ()*/ + {.w_px = 25, .glyph_index = 4650}, /*Unicode: U+f026 ()*/ + {.w_px = 25, .glyph_index = 5040}, /*Unicode: U+f027 ()*/ + {.w_px = 20, .glyph_index = 5430}, /*Unicode: U+f028 ()*/ + {.w_px = 20, .glyph_index = 5730}, /*Unicode: U+f03e ()*/ + {.w_px = 25, .glyph_index = 6030}, /*Unicode: U+f040 ()*/ + {.w_px = 20, .glyph_index = 6420}, /*Unicode: U+f048 ()*/ + {.w_px = 20, .glyph_index = 6720}, /*Unicode: U+f04b ()*/ + {.w_px = 20, .glyph_index = 7020}, /*Unicode: U+f04c ()*/ + {.w_px = 13, .glyph_index = 7320}, /*Unicode: U+f04d ()*/ + {.w_px = 32, .glyph_index = 7530}, /*Unicode: U+f051 ()*/ + {.w_px = 30, .glyph_index = 8010}, /*Unicode: U+f052 ()*/ + {.w_px = 16, .glyph_index = 8460}, /*Unicode: U+f053 ()*/ + {.w_px = 16, .glyph_index = 8700}, /*Unicode: U+f054 ()*/ + {.w_px = 25, .glyph_index = 8940}, /*Unicode: U+f067 ()*/ + {.w_px = 25, .glyph_index = 9330}, /*Unicode: U+f068 ()*/ + {.w_px = 27, .glyph_index = 9720}, /*Unicode: U+f071 ()*/ + {.w_px = 29, .glyph_index = 10140}, /*Unicode: U+f074 ()*/ + {.w_px = 26, .glyph_index = 10590}, /*Unicode: U+f077 ()*/ + {.w_px = 26, .glyph_index = 10980}, /*Unicode: U+f078 ()*/ + {.w_px = 25, .glyph_index = 11370}, /*Unicode: U+f079 ()*/ + {.w_px = 29, .glyph_index = 11760}, /*Unicode: U+f07b ()*/ + {.w_px = 25, .glyph_index = 12210}, /*Unicode: U+f093 ()*/ + {.w_px = 37, .glyph_index = 12600}, /*Unicode: U+f095 ()*/ + {.w_px = 25, .glyph_index = 13170}, /*Unicode: U+f0c4 ()*/ + {.w_px = 23, .glyph_index = 13560}, /*Unicode: U+f0c5 ()*/ + {.w_px = 24, .glyph_index = 13920}, /*Unicode: U+f0c7 ()*/ + {.w_px = 13, .glyph_index = 14280}, /*Unicode: U+f0e7 ()*/ + {.w_px = 18, .glyph_index = 14490}, /*Unicode: U+f0f3 ()*/ + {.w_px = 33, .glyph_index = 14760}, /*Unicode: U+f11c ()*/ + {.w_px = 25, .glyph_index = 15270}, /*Unicode: U+f124 ()*/ + {.w_px = 20, .glyph_index = 15660}, /*Unicode: U+f15b ()*/ + {.w_px = 29, .glyph_index = 15960}, /*Unicode: U+f1eb ()*/ + {.w_px = 38, .glyph_index = 16410}, /*Unicode: U+f240 ()*/ + {.w_px = 38, .glyph_index = 16980}, /*Unicode: U+f241 ()*/ + {.w_px = 38, .glyph_index = 17550}, /*Unicode: U+f242 ()*/ + {.w_px = 38, .glyph_index = 18120}, /*Unicode: U+f243 ()*/ + {.w_px = 38, .glyph_index = 18690}, /*Unicode: U+f244 ()*/ + {.w_px = 29, .glyph_index = 19260}, /*Unicode: U+f293 ()*/ + +#elif USE_HEKATE_SYMBOL_30 == 8 + {.w_px = 7, .glyph_index = 0}, /*Unicode: U+f001 ()*/ + {.w_px = 25, .glyph_index = 210}, /*Unicode: U+f008 ()*/ + {.w_px = 27, .glyph_index = 960}, /*Unicode: U+f00b ()*/ + {.w_px = 31, .glyph_index = 1770}, /*Unicode: U+f00c ()*/ + {.w_px = 22, .glyph_index = 2700}, /*Unicode: U+f00d ()*/ + {.w_px = 25, .glyph_index = 3360}, /*Unicode: U+f011 ()*/ + {.w_px = 25, .glyph_index = 4110}, /*Unicode: U+f013 ()*/ + {.w_px = 23, .glyph_index = 4860}, /*Unicode: U+f014 ()*/ + {.w_px = 34, .glyph_index = 5550}, /*Unicode: U+f015 ()*/ + {.w_px = 25, .glyph_index = 6570}, /*Unicode: U+f019 ()*/ + {.w_px = 32, .glyph_index = 7320}, /*Unicode: U+f01c ()*/ + {.w_px = 25, .glyph_index = 8280}, /*Unicode: U+f021 ()*/ + {.w_px = 25, .glyph_index = 9030}, /*Unicode: U+f026 ()*/ + {.w_px = 25, .glyph_index = 9780}, /*Unicode: U+f027 ()*/ + {.w_px = 20, .glyph_index = 10530}, /*Unicode: U+f028 ()*/ + {.w_px = 20, .glyph_index = 11130}, /*Unicode: U+f03e ()*/ + {.w_px = 25, .glyph_index = 11730}, /*Unicode: U+f040 ()*/ + {.w_px = 20, .glyph_index = 12480}, /*Unicode: U+f048 ()*/ + {.w_px = 20, .glyph_index = 13080}, /*Unicode: U+f04b ()*/ + {.w_px = 20, .glyph_index = 13680}, /*Unicode: U+f04c ()*/ + {.w_px = 13, .glyph_index = 14280}, /*Unicode: U+f04d ()*/ + {.w_px = 32, .glyph_index = 14670}, /*Unicode: U+f051 ()*/ + {.w_px = 30, .glyph_index = 15630}, /*Unicode: U+f052 ()*/ + {.w_px = 16, .glyph_index = 16530}, /*Unicode: U+f053 ()*/ + {.w_px = 16, .glyph_index = 17010}, /*Unicode: U+f054 ()*/ + {.w_px = 25, .glyph_index = 17490}, /*Unicode: U+f067 ()*/ + {.w_px = 25, .glyph_index = 18240}, /*Unicode: U+f068 ()*/ + {.w_px = 27, .glyph_index = 18990}, /*Unicode: U+f071 ()*/ + {.w_px = 29, .glyph_index = 19800}, /*Unicode: U+f074 ()*/ + {.w_px = 26, .glyph_index = 20670}, /*Unicode: U+f077 ()*/ + {.w_px = 26, .glyph_index = 21450}, /*Unicode: U+f078 ()*/ + {.w_px = 25, .glyph_index = 22230}, /*Unicode: U+f079 ()*/ + {.w_px = 29, .glyph_index = 22980}, /*Unicode: U+f07b ()*/ + {.w_px = 25, .glyph_index = 23850}, /*Unicode: U+f093 ()*/ + {.w_px = 37, .glyph_index = 24600}, /*Unicode: U+f095 ()*/ + {.w_px = 25, .glyph_index = 25710}, /*Unicode: U+f0c4 ()*/ + {.w_px = 23, .glyph_index = 26460}, /*Unicode: U+f0c5 ()*/ + {.w_px = 24, .glyph_index = 27150}, /*Unicode: U+f0c7 ()*/ + {.w_px = 13, .glyph_index = 27870}, /*Unicode: U+f0e7 ()*/ + {.w_px = 18, .glyph_index = 28260}, /*Unicode: U+f0f3 ()*/ + {.w_px = 33, .glyph_index = 28800}, /*Unicode: U+f11c ()*/ + {.w_px = 25, .glyph_index = 29790}, /*Unicode: U+f124 ()*/ + {.w_px = 20, .glyph_index = 30540}, /*Unicode: U+f15b ()*/ + {.w_px = 29, .glyph_index = 31140}, /*Unicode: U+f1eb ()*/ + {.w_px = 38, .glyph_index = 32010}, /*Unicode: U+f240 ()*/ + {.w_px = 38, .glyph_index = 33150}, /*Unicode: U+f241 ()*/ + {.w_px = 38, .glyph_index = 34290}, /*Unicode: U+f242 ()*/ + {.w_px = 38, .glyph_index = 35430}, /*Unicode: U+f243 ()*/ + {.w_px = 38, .glyph_index = 36570}, /*Unicode: U+f244 ()*/ + {.w_px = 29, .glyph_index = 37710}, /*Unicode: U+f293 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_30 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 30, /*Font height in pixels*/ + //.glyph_bitmap = hekate_symbol_30_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x14200), + .glyph_dsc = hekate_symbol_30_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 50, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_30 == 4 + .bpp = 4, /*Bit per pixel*/ + #elif USE_HEKATE_SYMBOL_30 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_30*/ diff --git a/bdk/libs/lvgl/lv_fonts/interui_20.c b/bdk/libs/lvgl/lv_fonts/interui_20.c new file mode 100644 index 0000000..5f50c6c --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/interui_20.c @@ -0,0 +1,248 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_INTERUI_20 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * Inter-UI-Regular-stretched.ttf 20 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t interui_20_glyph_dsc[] = +{ +#if USE_INTERUI_20 == 4 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 60}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 100}, /*Unicode: U+0022 (")*/ + {.w_px = 8, .glyph_index = 160}, /*Unicode: U+0023 (#)*/ + {.w_px = 9, .glyph_index = 240}, /*Unicode: U+0024 ($)*/ + {.w_px = 14, .glyph_index = 340}, /*Unicode: U+0025 (%)*/ + {.w_px = 12, .glyph_index = 480}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 600}, /*Unicode: U+0027 (')*/ + {.w_px = 5, .glyph_index = 640}, /*Unicode: U+0028 (()*/ + {.w_px = 5, .glyph_index = 700}, /*Unicode: U+0029 ())*/ + {.w_px = 7, .glyph_index = 760}, /*Unicode: U+002a (*)*/ + {.w_px = 10, .glyph_index = 840}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 940}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 980}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 1040}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1080}, /*Unicode: U+002f (/)*/ + {.w_px = 10, .glyph_index = 1160}, /*Unicode: U+0030 (0)*/ + {.w_px = 5, .glyph_index = 1260}, /*Unicode: U+0031 (1)*/ + {.w_px = 9, .glyph_index = 1320}, /*Unicode: U+0032 (2)*/ + {.w_px = 10, .glyph_index = 1420}, /*Unicode: U+0033 (3)*/ + {.w_px = 9, .glyph_index = 1520}, /*Unicode: U+0034 (4)*/ + {.w_px = 9, .glyph_index = 1620}, /*Unicode: U+0035 (5)*/ + {.w_px = 10, .glyph_index = 1720}, /*Unicode: U+0036 (6)*/ + {.w_px = 8, .glyph_index = 1820}, /*Unicode: U+0037 (7)*/ + {.w_px = 10, .glyph_index = 1900}, /*Unicode: U+0038 (8)*/ + {.w_px = 10, .glyph_index = 2000}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 2100}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 2140}, /*Unicode: U+003b (;)*/ + {.w_px = 12, .glyph_index = 2180}, /*Unicode: U+003c (<)*/ + {.w_px = 10, .glyph_index = 2300}, /*Unicode: U+003d (=)*/ + {.w_px = 12, .glyph_index = 2400}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 2520}, /*Unicode: U+003f (?)*/ + {.w_px = 14, .glyph_index = 2600}, /*Unicode: U+0040 (@)*/ + {.w_px = 12, .glyph_index = 2740}, /*Unicode: U+0041 (A)*/ + {.w_px = 10, .glyph_index = 2860}, /*Unicode: U+0042 (B)*/ + {.w_px = 11, .glyph_index = 2960}, /*Unicode: U+0043 (C)*/ + {.w_px = 12, .glyph_index = 3080}, /*Unicode: U+0044 (D)*/ + {.w_px = 9, .glyph_index = 3200}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+0046 (F)*/ + {.w_px = 12, .glyph_index = 3380}, /*Unicode: U+0047 (G)*/ + {.w_px = 10, .glyph_index = 3500}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 3600}, /*Unicode: U+0049 (I)*/ + {.w_px = 7, .glyph_index = 3640}, /*Unicode: U+004a (J)*/ + {.w_px = 10, .glyph_index = 3720}, /*Unicode: U+004b (K)*/ + {.w_px = 7, .glyph_index = 3820}, /*Unicode: U+004c (L)*/ + {.w_px = 15, .glyph_index = 3900}, /*Unicode: U+004d (M)*/ + {.w_px = 12, .glyph_index = 4060}, /*Unicode: U+004e (N)*/ + {.w_px = 14, .glyph_index = 4180}, /*Unicode: U+004f (O)*/ + {.w_px = 9, .glyph_index = 4320}, /*Unicode: U+0050 (P)*/ + {.w_px = 14, .glyph_index = 4420}, /*Unicode: U+0051 (Q)*/ + {.w_px = 9, .glyph_index = 4560}, /*Unicode: U+0052 (R)*/ + {.w_px = 9, .glyph_index = 4660}, /*Unicode: U+0053 (S)*/ + {.w_px = 9, .glyph_index = 4760}, /*Unicode: U+0054 (T)*/ + {.w_px = 12, .glyph_index = 4860}, /*Unicode: U+0055 (U)*/ + {.w_px = 12, .glyph_index = 4980}, /*Unicode: U+0056 (V)*/ + {.w_px = 18, .glyph_index = 5100}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 5280}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 5380}, /*Unicode: U+0059 (Y)*/ + {.w_px = 10, .glyph_index = 5480}, /*Unicode: U+005a (Z)*/ + {.w_px = 5, .glyph_index = 5580}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 5640}, /*Unicode: U+005c (\)*/ + {.w_px = 5, .glyph_index = 5720}, /*Unicode: U+005d (])*/ + {.w_px = 9, .glyph_index = 5780}, /*Unicode: U+005e (^)*/ + {.w_px = 8, .glyph_index = 5880}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 5960}, /*Unicode: U+0060 (`)*/ + {.w_px = 9, .glyph_index = 6000}, /*Unicode: U+0061 (a)*/ + {.w_px = 10, .glyph_index = 6100}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 6200}, /*Unicode: U+0063 (c)*/ + {.w_px = 10, .glyph_index = 6280}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 6380}, /*Unicode: U+0065 (e)*/ + {.w_px = 4, .glyph_index = 6480}, /*Unicode: U+0066 (f)*/ + {.w_px = 9, .glyph_index = 6520}, /*Unicode: U+0067 (g)*/ + {.w_px = 9, .glyph_index = 6620}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 6720}, /*Unicode: U+0069 (i)*/ + {.w_px = 5, .glyph_index = 6760}, /*Unicode: U+006a (j)*/ + {.w_px = 8, .glyph_index = 6820}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 6900}, /*Unicode: U+006c (l)*/ + {.w_px = 13, .glyph_index = 6940}, /*Unicode: U+006d (m)*/ + {.w_px = 9, .glyph_index = 7080}, /*Unicode: U+006e (n)*/ + {.w_px = 10, .glyph_index = 7180}, /*Unicode: U+006f (o)*/ + {.w_px = 10, .glyph_index = 7280}, /*Unicode: U+0070 (p)*/ + {.w_px = 10, .glyph_index = 7380}, /*Unicode: U+0071 (q)*/ + {.w_px = 5, .glyph_index = 7480}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 7540}, /*Unicode: U+0073 (s)*/ + {.w_px = 5, .glyph_index = 7620}, /*Unicode: U+0074 (t)*/ + {.w_px = 9, .glyph_index = 7680}, /*Unicode: U+0075 (u)*/ + {.w_px = 8, .glyph_index = 7780}, /*Unicode: U+0076 (v)*/ + {.w_px = 14, .glyph_index = 7860}, /*Unicode: U+0077 (w)*/ + {.w_px = 8, .glyph_index = 8000}, /*Unicode: U+0078 (x)*/ + {.w_px = 8, .glyph_index = 8080}, /*Unicode: U+0079 (y)*/ + {.w_px = 7, .glyph_index = 8160}, /*Unicode: U+007a (z)*/ + {.w_px = 4, .glyph_index = 8240}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 8280}, /*Unicode: U+007c (|)*/ + {.w_px = 4, .glyph_index = 8320}, /*Unicode: U+007d (})*/ + {.w_px = 6, .glyph_index = 8360}, /*Unicode: U+007e (~)*/ + +#elif USE_INTERUI_20 == 8 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 180}, /*Unicode: U+0022 (")*/ + {.w_px = 8, .glyph_index = 280}, /*Unicode: U+0023 (#)*/ + {.w_px = 9, .glyph_index = 440}, /*Unicode: U+0024 ($)*/ + {.w_px = 14, .glyph_index = 620}, /*Unicode: U+0025 (%)*/ + {.w_px = 12, .glyph_index = 900}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 1140}, /*Unicode: U+0027 (')*/ + {.w_px = 5, .glyph_index = 1200}, /*Unicode: U+0028 (()*/ + {.w_px = 5, .glyph_index = 1300}, /*Unicode: U+0029 ())*/ + {.w_px = 7, .glyph_index = 1400}, /*Unicode: U+002a (*)*/ + {.w_px = 10, .glyph_index = 1540}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 1740}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 1800}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 1900}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1960}, /*Unicode: U+002f (/)*/ + {.w_px = 10, .glyph_index = 2120}, /*Unicode: U+0030 (0)*/ + {.w_px = 5, .glyph_index = 2320}, /*Unicode: U+0031 (1)*/ + {.w_px = 9, .glyph_index = 2420}, /*Unicode: U+0032 (2)*/ + {.w_px = 10, .glyph_index = 2600}, /*Unicode: U+0033 (3)*/ + {.w_px = 9, .glyph_index = 2800}, /*Unicode: U+0034 (4)*/ + {.w_px = 9, .glyph_index = 2980}, /*Unicode: U+0035 (5)*/ + {.w_px = 10, .glyph_index = 3160}, /*Unicode: U+0036 (6)*/ + {.w_px = 8, .glyph_index = 3360}, /*Unicode: U+0037 (7)*/ + {.w_px = 10, .glyph_index = 3520}, /*Unicode: U+0038 (8)*/ + {.w_px = 10, .glyph_index = 3720}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 3920}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 3980}, /*Unicode: U+003b (;)*/ + {.w_px = 12, .glyph_index = 4040}, /*Unicode: U+003c (<)*/ + {.w_px = 10, .glyph_index = 4280}, /*Unicode: U+003d (=)*/ + {.w_px = 12, .glyph_index = 4480}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 4720}, /*Unicode: U+003f (?)*/ + {.w_px = 14, .glyph_index = 4880}, /*Unicode: U+0040 (@)*/ + {.w_px = 12, .glyph_index = 5160}, /*Unicode: U+0041 (A)*/ + {.w_px = 10, .glyph_index = 5400}, /*Unicode: U+0042 (B)*/ + {.w_px = 11, .glyph_index = 5600}, /*Unicode: U+0043 (C)*/ + {.w_px = 12, .glyph_index = 5820}, /*Unicode: U+0044 (D)*/ + {.w_px = 9, .glyph_index = 6060}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 6240}, /*Unicode: U+0046 (F)*/ + {.w_px = 12, .glyph_index = 6400}, /*Unicode: U+0047 (G)*/ + {.w_px = 10, .glyph_index = 6640}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 6840}, /*Unicode: U+0049 (I)*/ + {.w_px = 7, .glyph_index = 6900}, /*Unicode: U+004a (J)*/ + {.w_px = 10, .glyph_index = 7040}, /*Unicode: U+004b (K)*/ + {.w_px = 7, .glyph_index = 7240}, /*Unicode: U+004c (L)*/ + {.w_px = 15, .glyph_index = 7380}, /*Unicode: U+004d (M)*/ + {.w_px = 12, .glyph_index = 7680}, /*Unicode: U+004e (N)*/ + {.w_px = 14, .glyph_index = 7920}, /*Unicode: U+004f (O)*/ + {.w_px = 9, .glyph_index = 8200}, /*Unicode: U+0050 (P)*/ + {.w_px = 14, .glyph_index = 8380}, /*Unicode: U+0051 (Q)*/ + {.w_px = 9, .glyph_index = 8660}, /*Unicode: U+0052 (R)*/ + {.w_px = 9, .glyph_index = 8840}, /*Unicode: U+0053 (S)*/ + {.w_px = 9, .glyph_index = 9020}, /*Unicode: U+0054 (T)*/ + {.w_px = 12, .glyph_index = 9200}, /*Unicode: U+0055 (U)*/ + {.w_px = 12, .glyph_index = 9440}, /*Unicode: U+0056 (V)*/ + {.w_px = 18, .glyph_index = 9680}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 10040}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 10240}, /*Unicode: U+0059 (Y)*/ + {.w_px = 10, .glyph_index = 10440}, /*Unicode: U+005a (Z)*/ + {.w_px = 5, .glyph_index = 10640}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 10740}, /*Unicode: U+005c (\)*/ + {.w_px = 5, .glyph_index = 10900}, /*Unicode: U+005d (])*/ + {.w_px = 9, .glyph_index = 11000}, /*Unicode: U+005e (^)*/ + {.w_px = 8, .glyph_index = 11180}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 11340}, /*Unicode: U+0060 (`)*/ + {.w_px = 9, .glyph_index = 11420}, /*Unicode: U+0061 (a)*/ + {.w_px = 10, .glyph_index = 11600}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 11800}, /*Unicode: U+0063 (c)*/ + {.w_px = 10, .glyph_index = 11960}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 12160}, /*Unicode: U+0065 (e)*/ + {.w_px = 4, .glyph_index = 12340}, /*Unicode: U+0066 (f)*/ + {.w_px = 9, .glyph_index = 12420}, /*Unicode: U+0067 (g)*/ + {.w_px = 9, .glyph_index = 12600}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 12780}, /*Unicode: U+0069 (i)*/ + {.w_px = 5, .glyph_index = 12840}, /*Unicode: U+006a (j)*/ + {.w_px = 8, .glyph_index = 12940}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 13100}, /*Unicode: U+006c (l)*/ + {.w_px = 13, .glyph_index = 13180}, /*Unicode: U+006d (m)*/ + {.w_px = 9, .glyph_index = 13440}, /*Unicode: U+006e (n)*/ + {.w_px = 10, .glyph_index = 13620}, /*Unicode: U+006f (o)*/ + {.w_px = 10, .glyph_index = 13820}, /*Unicode: U+0070 (p)*/ + {.w_px = 10, .glyph_index = 14020}, /*Unicode: U+0071 (q)*/ + {.w_px = 5, .glyph_index = 14220}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 14320}, /*Unicode: U+0073 (s)*/ + {.w_px = 5, .glyph_index = 14480}, /*Unicode: U+0074 (t)*/ + {.w_px = 9, .glyph_index = 14580}, /*Unicode: U+0075 (u)*/ + {.w_px = 8, .glyph_index = 14760}, /*Unicode: U+0076 (v)*/ + {.w_px = 14, .glyph_index = 14920}, /*Unicode: U+0077 (w)*/ + {.w_px = 8, .glyph_index = 15200}, /*Unicode: U+0078 (x)*/ + {.w_px = 8, .glyph_index = 15360}, /*Unicode: U+0079 (y)*/ + {.w_px = 7, .glyph_index = 15520}, /*Unicode: U+007a (z)*/ + {.w_px = 4, .glyph_index = 15660}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 15740}, /*Unicode: U+007c (|)*/ + {.w_px = 4, .glyph_index = 15800}, /*Unicode: U+007d (})*/ + {.w_px = 6, .glyph_index = 15880}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t interui_20 = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = interui_20_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x3A00), + .glyph_dsc = interui_20_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_INTERUI_20 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_INTERUI_20 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_INTERUI_20*/ diff --git a/bdk/libs/lvgl/lv_fonts/interui_30.c b/bdk/libs/lvgl/lv_fonts/interui_30.c new file mode 100644 index 0000000..238bcb1 --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/interui_30.c @@ -0,0 +1,248 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_INTERUI_30 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * Inter-UI-Regular-stretched.ttf 30 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t interui_30_glyph_dsc[] = +{ +#if USE_INTERUI_30 == 4 + {.w_px = 8, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 6, .glyph_index = 180}, /*Unicode: U+0022 (")*/ + {.w_px = 13, .glyph_index = 270}, /*Unicode: U+0023 (#)*/ + {.w_px = 12, .glyph_index = 480}, /*Unicode: U+0024 ($)*/ + {.w_px = 18, .glyph_index = 660}, /*Unicode: U+0025 (%)*/ + {.w_px = 16, .glyph_index = 930}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 1170}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 1230}, /*Unicode: U+0028 (()*/ + {.w_px = 7, .glyph_index = 1320}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 1440}, /*Unicode: U+002a (*)*/ + {.w_px = 16, .glyph_index = 1590}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 1830}, /*Unicode: U+002c (,)*/ + {.w_px = 8, .glyph_index = 1890}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 2010}, /*Unicode: U+002e (.)*/ + {.w_px = 11, .glyph_index = 2070}, /*Unicode: U+002f (/)*/ + {.w_px = 13, .glyph_index = 2250}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 2460}, /*Unicode: U+0031 (1)*/ + {.w_px = 13, .glyph_index = 2580}, /*Unicode: U+0032 (2)*/ + {.w_px = 14, .glyph_index = 2790}, /*Unicode: U+0033 (3)*/ + {.w_px = 13, .glyph_index = 3000}, /*Unicode: U+0034 (4)*/ + {.w_px = 14, .glyph_index = 3210}, /*Unicode: U+0035 (5)*/ + {.w_px = 13, .glyph_index = 3420}, /*Unicode: U+0036 (6)*/ + {.w_px = 13, .glyph_index = 3630}, /*Unicode: U+0037 (7)*/ + {.w_px = 13, .glyph_index = 3840}, /*Unicode: U+0038 (8)*/ + {.w_px = 13, .glyph_index = 4050}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 4260}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 4320}, /*Unicode: U+003b (;)*/ + {.w_px = 18, .glyph_index = 4380}, /*Unicode: U+003c (<)*/ + {.w_px = 16, .glyph_index = 4650}, /*Unicode: U+003d (=)*/ + {.w_px = 18, .glyph_index = 4890}, /*Unicode: U+003e (>)*/ + {.w_px = 12, .glyph_index = 5160}, /*Unicode: U+003f (?)*/ + {.w_px = 18, .glyph_index = 5340}, /*Unicode: U+0040 (@)*/ + {.w_px = 17, .glyph_index = 5610}, /*Unicode: U+0041 (A)*/ + {.w_px = 13, .glyph_index = 5880}, /*Unicode: U+0042 (B)*/ + {.w_px = 15, .glyph_index = 6090}, /*Unicode: U+0043 (C)*/ + {.w_px = 17, .glyph_index = 6330}, /*Unicode: U+0044 (D)*/ + {.w_px = 12, .glyph_index = 6600}, /*Unicode: U+0045 (E)*/ + {.w_px = 11, .glyph_index = 6780}, /*Unicode: U+0046 (F)*/ + {.w_px = 17, .glyph_index = 6960}, /*Unicode: U+0047 (G)*/ + {.w_px = 14, .glyph_index = 7230}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 7440}, /*Unicode: U+0049 (I)*/ + {.w_px = 11, .glyph_index = 7500}, /*Unicode: U+004a (J)*/ + {.w_px = 14, .glyph_index = 7680}, /*Unicode: U+004b (K)*/ + {.w_px = 9, .glyph_index = 7890}, /*Unicode: U+004c (L)*/ + {.w_px = 23, .glyph_index = 8040}, /*Unicode: U+004d (M)*/ + {.w_px = 16, .glyph_index = 8400}, /*Unicode: U+004e (N)*/ + {.w_px = 19, .glyph_index = 8640}, /*Unicode: U+004f (O)*/ + {.w_px = 11, .glyph_index = 8940}, /*Unicode: U+0050 (P)*/ + {.w_px = 19, .glyph_index = 9120}, /*Unicode: U+0051 (Q)*/ + {.w_px = 13, .glyph_index = 9420}, /*Unicode: U+0052 (R)*/ + {.w_px = 12, .glyph_index = 9630}, /*Unicode: U+0053 (S)*/ + {.w_px = 14, .glyph_index = 9810}, /*Unicode: U+0054 (T)*/ + {.w_px = 16, .glyph_index = 10020}, /*Unicode: U+0055 (U)*/ + {.w_px = 18, .glyph_index = 10260}, /*Unicode: U+0056 (V)*/ + {.w_px = 27, .glyph_index = 10530}, /*Unicode: U+0057 (W)*/ + {.w_px = 15, .glyph_index = 10950}, /*Unicode: U+0058 (X)*/ + {.w_px = 15, .glyph_index = 11190}, /*Unicode: U+0059 (Y)*/ + {.w_px = 15, .glyph_index = 11430}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 11670}, /*Unicode: U+005b ([)*/ + {.w_px = 11, .glyph_index = 11760}, /*Unicode: U+005c (\)*/ + {.w_px = 7, .glyph_index = 11940}, /*Unicode: U+005d (])*/ + {.w_px = 13, .glyph_index = 12060}, /*Unicode: U+005e (^)*/ + {.w_px = 12, .glyph_index = 12270}, /*Unicode: U+005f (_)*/ + {.w_px = 6, .glyph_index = 12450}, /*Unicode: U+0060 (`)*/ + {.w_px = 12, .glyph_index = 12540}, /*Unicode: U+0061 (a)*/ + {.w_px = 13, .glyph_index = 12720}, /*Unicode: U+0062 (b)*/ + {.w_px = 11, .glyph_index = 12930}, /*Unicode: U+0063 (c)*/ + {.w_px = 13, .glyph_index = 13110}, /*Unicode: U+0064 (d)*/ + {.w_px = 12, .glyph_index = 13320}, /*Unicode: U+0065 (e)*/ + {.w_px = 6, .glyph_index = 13500}, /*Unicode: U+0066 (f)*/ + {.w_px = 12, .glyph_index = 13590}, /*Unicode: U+0067 (g)*/ + {.w_px = 11, .glyph_index = 13770}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 13950}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 14010}, /*Unicode: U+006a (j)*/ + {.w_px = 12, .glyph_index = 14130}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 14310}, /*Unicode: U+006c (l)*/ + {.w_px = 19, .glyph_index = 14370}, /*Unicode: U+006d (m)*/ + {.w_px = 11, .glyph_index = 14670}, /*Unicode: U+006e (n)*/ + {.w_px = 14, .glyph_index = 14850}, /*Unicode: U+006f (o)*/ + {.w_px = 13, .glyph_index = 15060}, /*Unicode: U+0070 (p)*/ + {.w_px = 13, .glyph_index = 15270}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 15480}, /*Unicode: U+0072 (r)*/ + {.w_px = 11, .glyph_index = 15600}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 15780}, /*Unicode: U+0074 (t)*/ + {.w_px = 11, .glyph_index = 15900}, /*Unicode: U+0075 (u)*/ + {.w_px = 12, .glyph_index = 16080}, /*Unicode: U+0076 (v)*/ + {.w_px = 21, .glyph_index = 16260}, /*Unicode: U+0077 (w)*/ + {.w_px = 13, .glyph_index = 16590}, /*Unicode: U+0078 (x)*/ + {.w_px = 13, .glyph_index = 16800}, /*Unicode: U+0079 (y)*/ + {.w_px = 10, .glyph_index = 17010}, /*Unicode: U+007a (z)*/ + {.w_px = 6, .glyph_index = 17160}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 17250}, /*Unicode: U+007c (|)*/ + {.w_px = 5, .glyph_index = 17310}, /*Unicode: U+007d (})*/ + {.w_px = 8, .glyph_index = 17400}, /*Unicode: U+007e (~)*/ + +#elif USE_INTERUI_30 == 8 + {.w_px = 8, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 240}, /*Unicode: U+0021 (!)*/ + {.w_px = 6, .glyph_index = 330}, /*Unicode: U+0022 (")*/ + {.w_px = 13, .glyph_index = 510}, /*Unicode: U+0023 (#)*/ + {.w_px = 12, .glyph_index = 900}, /*Unicode: U+0024 ($)*/ + {.w_px = 18, .glyph_index = 1260}, /*Unicode: U+0025 (%)*/ + {.w_px = 16, .glyph_index = 1800}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 2280}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 2370}, /*Unicode: U+0028 (()*/ + {.w_px = 7, .glyph_index = 2550}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 2760}, /*Unicode: U+002a (*)*/ + {.w_px = 16, .glyph_index = 3030}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 3510}, /*Unicode: U+002c (,)*/ + {.w_px = 8, .glyph_index = 3600}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 3840}, /*Unicode: U+002e (.)*/ + {.w_px = 11, .glyph_index = 3930}, /*Unicode: U+002f (/)*/ + {.w_px = 13, .glyph_index = 4260}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 4650}, /*Unicode: U+0031 (1)*/ + {.w_px = 13, .glyph_index = 4860}, /*Unicode: U+0032 (2)*/ + {.w_px = 14, .glyph_index = 5250}, /*Unicode: U+0033 (3)*/ + {.w_px = 13, .glyph_index = 5670}, /*Unicode: U+0034 (4)*/ + {.w_px = 14, .glyph_index = 6060}, /*Unicode: U+0035 (5)*/ + {.w_px = 13, .glyph_index = 6480}, /*Unicode: U+0036 (6)*/ + {.w_px = 13, .glyph_index = 6870}, /*Unicode: U+0037 (7)*/ + {.w_px = 13, .glyph_index = 7260}, /*Unicode: U+0038 (8)*/ + {.w_px = 13, .glyph_index = 7650}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 8040}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 8130}, /*Unicode: U+003b (;)*/ + {.w_px = 18, .glyph_index = 8220}, /*Unicode: U+003c (<)*/ + {.w_px = 16, .glyph_index = 8760}, /*Unicode: U+003d (=)*/ + {.w_px = 18, .glyph_index = 9240}, /*Unicode: U+003e (>)*/ + {.w_px = 12, .glyph_index = 9780}, /*Unicode: U+003f (?)*/ + {.w_px = 18, .glyph_index = 10140}, /*Unicode: U+0040 (@)*/ + {.w_px = 17, .glyph_index = 10680}, /*Unicode: U+0041 (A)*/ + {.w_px = 13, .glyph_index = 11190}, /*Unicode: U+0042 (B)*/ + {.w_px = 15, .glyph_index = 11580}, /*Unicode: U+0043 (C)*/ + {.w_px = 17, .glyph_index = 12030}, /*Unicode: U+0044 (D)*/ + {.w_px = 12, .glyph_index = 12540}, /*Unicode: U+0045 (E)*/ + {.w_px = 11, .glyph_index = 12900}, /*Unicode: U+0046 (F)*/ + {.w_px = 17, .glyph_index = 13230}, /*Unicode: U+0047 (G)*/ + {.w_px = 14, .glyph_index = 13740}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 14160}, /*Unicode: U+0049 (I)*/ + {.w_px = 11, .glyph_index = 14250}, /*Unicode: U+004a (J)*/ + {.w_px = 14, .glyph_index = 14580}, /*Unicode: U+004b (K)*/ + {.w_px = 9, .glyph_index = 15000}, /*Unicode: U+004c (L)*/ + {.w_px = 23, .glyph_index = 15270}, /*Unicode: U+004d (M)*/ + {.w_px = 16, .glyph_index = 15960}, /*Unicode: U+004e (N)*/ + {.w_px = 19, .glyph_index = 16440}, /*Unicode: U+004f (O)*/ + {.w_px = 11, .glyph_index = 17010}, /*Unicode: U+0050 (P)*/ + {.w_px = 19, .glyph_index = 17340}, /*Unicode: U+0051 (Q)*/ + {.w_px = 13, .glyph_index = 17910}, /*Unicode: U+0052 (R)*/ + {.w_px = 12, .glyph_index = 18300}, /*Unicode: U+0053 (S)*/ + {.w_px = 14, .glyph_index = 18660}, /*Unicode: U+0054 (T)*/ + {.w_px = 16, .glyph_index = 19080}, /*Unicode: U+0055 (U)*/ + {.w_px = 18, .glyph_index = 19560}, /*Unicode: U+0056 (V)*/ + {.w_px = 27, .glyph_index = 20100}, /*Unicode: U+0057 (W)*/ + {.w_px = 15, .glyph_index = 20910}, /*Unicode: U+0058 (X)*/ + {.w_px = 15, .glyph_index = 21360}, /*Unicode: U+0059 (Y)*/ + {.w_px = 15, .glyph_index = 21810}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 22260}, /*Unicode: U+005b ([)*/ + {.w_px = 11, .glyph_index = 22440}, /*Unicode: U+005c (\)*/ + {.w_px = 7, .glyph_index = 22770}, /*Unicode: U+005d (])*/ + {.w_px = 13, .glyph_index = 22980}, /*Unicode: U+005e (^)*/ + {.w_px = 12, .glyph_index = 23370}, /*Unicode: U+005f (_)*/ + {.w_px = 6, .glyph_index = 23730}, /*Unicode: U+0060 (`)*/ + {.w_px = 12, .glyph_index = 23910}, /*Unicode: U+0061 (a)*/ + {.w_px = 13, .glyph_index = 24270}, /*Unicode: U+0062 (b)*/ + {.w_px = 11, .glyph_index = 24660}, /*Unicode: U+0063 (c)*/ + {.w_px = 13, .glyph_index = 24990}, /*Unicode: U+0064 (d)*/ + {.w_px = 12, .glyph_index = 25380}, /*Unicode: U+0065 (e)*/ + {.w_px = 6, .glyph_index = 25740}, /*Unicode: U+0066 (f)*/ + {.w_px = 12, .glyph_index = 25920}, /*Unicode: U+0067 (g)*/ + {.w_px = 11, .glyph_index = 26280}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 26610}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 26700}, /*Unicode: U+006a (j)*/ + {.w_px = 12, .glyph_index = 26910}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 27270}, /*Unicode: U+006c (l)*/ + {.w_px = 19, .glyph_index = 27390}, /*Unicode: U+006d (m)*/ + {.w_px = 11, .glyph_index = 27960}, /*Unicode: U+006e (n)*/ + {.w_px = 14, .glyph_index = 28290}, /*Unicode: U+006f (o)*/ + {.w_px = 13, .glyph_index = 28710}, /*Unicode: U+0070 (p)*/ + {.w_px = 13, .glyph_index = 29100}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 29490}, /*Unicode: U+0072 (r)*/ + {.w_px = 11, .glyph_index = 29700}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 30030}, /*Unicode: U+0074 (t)*/ + {.w_px = 11, .glyph_index = 30270}, /*Unicode: U+0075 (u)*/ + {.w_px = 12, .glyph_index = 30600}, /*Unicode: U+0076 (v)*/ + {.w_px = 21, .glyph_index = 30960}, /*Unicode: U+0077 (w)*/ + {.w_px = 13, .glyph_index = 31590}, /*Unicode: U+0078 (x)*/ + {.w_px = 13, .glyph_index = 31980}, /*Unicode: U+0079 (y)*/ + {.w_px = 10, .glyph_index = 32370}, /*Unicode: U+007a (z)*/ + {.w_px = 6, .glyph_index = 32670}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 32850}, /*Unicode: U+007c (|)*/ + {.w_px = 5, .glyph_index = 32940}, /*Unicode: U+007d (})*/ + {.w_px = 8, .glyph_index = 33090}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t interui_30 = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 30, /*Font height in pixels*/ + //.glyph_bitmap = interui_30_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x7900), + .glyph_dsc = interui_30_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_INTERUI_30 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_INTERUI_30 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_INTERUI_30*/ diff --git a/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c new file mode 100644 index 0000000..16cbaea --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c @@ -0,0 +1,100 @@ +/* + * 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 . + */ + +/** + * @file lv_font_built_in.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_font_builtin.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void) +{ + /*InterUI 20*/ +#if USE_INTERUI_20 != 0 + lv_font_add(&interui_20, NULL); +#endif + + /*SYMBOL 20*/ +#if USE_HEKATE_SYMBOL_20 != 0 +#if USE_INTERUI_20 != 0 + lv_font_add(&hekate_symbol_20, &interui_20); +#else + lv_font_add(&hekate_symbol_20, NULL); +#endif +#endif + + /*InterUI 30*/ +#if USE_INTERUI_30 != 0 + lv_font_add(&interui_30, NULL); +#endif + + /*SYMBOL 30*/ +#if USE_HEKATE_SYMBOL_30 != 0 +#if USE_INTERUI_30 != 0 + lv_font_add(&hekate_symbol_30, &interui_30); +#else + lv_font_add(&hekate_symbol_30, NULL); +#endif +#endif + + /*MONO 12*/ +#if USE_UBUNTU_MONO != 0 + lv_font_add(&ubuntu_mono, NULL); +#if USE_INTERUI_20 != 0 + lv_font_add(&hekate_symbol_20, &ubuntu_mono); +#endif +#endif + + /*Symbol 120*/ +#if USE_HEKATE_SYMBOL_120 != 0 + lv_font_add(&hekate_symbol_120, NULL); +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h new file mode 100644 index 0000000..519471f --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h @@ -0,0 +1,95 @@ +/* + * 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 . + */ + +/** + * @file lv_font_builtin.h + * + */ + +#ifndef LV_FONT_BUILTIN_H +#define LV_FONT_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void); + +/********************** + * MACROS + **********************/ + +/********************** + * FONT DECLARATIONS + **********************/ + +/*20 px */ +#if USE_INTERUI_20 +LV_FONT_DECLARE(interui_20); +#endif + +#if USE_HEKATE_SYMBOL_20 +LV_FONT_DECLARE(hekate_symbol_20); +#endif + +/*30 px */ +#if USE_INTERUI_30 +LV_FONT_DECLARE(interui_30); +#endif + +#if USE_HEKATE_SYMBOL_30 +LV_FONT_DECLARE(hekate_symbol_30); +#endif + +#if USE_UBUNTU_MONO +LV_FONT_DECLARE(ubuntu_mono); +#endif + +#if USE_HEKATE_SYMBOL_120 +LV_FONT_DECLARE(hekate_symbol_120); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FONT_BUILTIN_H*/ diff --git a/bdk/libs/lvgl/lv_fonts/lv_fonts.mk b/bdk/libs/lvgl/lv_fonts/lv_fonts.mk new file mode 100644 index 0000000..d288f8a --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/lv_fonts.mk @@ -0,0 +1,14 @@ +CSRCS += lv_font_builtin.c +CSRCS += hekate_symbol_10.c +CSRCS += hekate_symbol_20.c +CSRCS += hekate_symbol_30.c +CSRCS += hekate_symbol_40.c +CSRCS += interui_12.c +CSRCS += interui_20.c +CSRCS += interui_30.c +CSRCS += interui_40.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts +VPATH += :$(LVGL_DIR)/lvgl/lv_fonts + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts" diff --git a/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c b/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c new file mode 100644 index 0000000..4c988fc --- /dev/null +++ b/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c @@ -0,0 +1,248 @@ +/* + * 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 . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_UBUNTU_MONO != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * UbuntuMono-B.ttf 20 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t ubuntu_mono_glyph_dsc[] = +{ +#if USE_UBUNTU_MONO == 4 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 2, .glyph_index = 60}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 80}, /*Unicode: U+0022 (")*/ + {.w_px = 10, .glyph_index = 140}, /*Unicode: U+0023 (#)*/ + {.w_px = 8, .glyph_index = 240}, /*Unicode: U+0024 ($)*/ + {.w_px = 10, .glyph_index = 320}, /*Unicode: U+0025 (%)*/ + {.w_px = 10, .glyph_index = 420}, /*Unicode: U+0026 (&)*/ + {.w_px = 2, .glyph_index = 520}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 540}, /*Unicode: U+0028 (()*/ + {.w_px = 6, .glyph_index = 600}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 660}, /*Unicode: U+002a (*)*/ + {.w_px = 8, .glyph_index = 760}, /*Unicode: U+002b (+)*/ + {.w_px = 4, .glyph_index = 840}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 880}, /*Unicode: U+002d (-)*/ + {.w_px = 4, .glyph_index = 940}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 980}, /*Unicode: U+002f (/)*/ + {.w_px = 8, .glyph_index = 1060}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 1140}, /*Unicode: U+0031 (1)*/ + {.w_px = 8, .glyph_index = 1220}, /*Unicode: U+0032 (2)*/ + {.w_px = 8, .glyph_index = 1300}, /*Unicode: U+0033 (3)*/ + {.w_px = 8, .glyph_index = 1380}, /*Unicode: U+0034 (4)*/ + {.w_px = 8, .glyph_index = 1460}, /*Unicode: U+0035 (5)*/ + {.w_px = 8, .glyph_index = 1540}, /*Unicode: U+0036 (6)*/ + {.w_px = 7, .glyph_index = 1620}, /*Unicode: U+0037 (7)*/ + {.w_px = 8, .glyph_index = 1700}, /*Unicode: U+0038 (8)*/ + {.w_px = 8, .glyph_index = 1780}, /*Unicode: U+0039 (9)*/ + {.w_px = 4, .glyph_index = 1860}, /*Unicode: U+003a (:)*/ + {.w_px = 4, .glyph_index = 1900}, /*Unicode: U+003b (;)*/ + {.w_px = 9, .glyph_index = 1940}, /*Unicode: U+003c (<)*/ + {.w_px = 8, .glyph_index = 2040}, /*Unicode: U+003d (=)*/ + {.w_px = 8, .glyph_index = 2120}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 2200}, /*Unicode: U+003f (?)*/ + {.w_px = 9, .glyph_index = 2280}, /*Unicode: U+0040 (@)*/ + {.w_px = 10, .glyph_index = 2380}, /*Unicode: U+0041 (A)*/ + {.w_px = 8, .glyph_index = 2480}, /*Unicode: U+0042 (B)*/ + {.w_px = 8, .glyph_index = 2560}, /*Unicode: U+0043 (C)*/ + {.w_px = 8, .glyph_index = 2640}, /*Unicode: U+0044 (D)*/ + {.w_px = 8, .glyph_index = 2720}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 2800}, /*Unicode: U+0046 (F)*/ + {.w_px = 8, .glyph_index = 2880}, /*Unicode: U+0047 (G)*/ + {.w_px = 8, .glyph_index = 2960}, /*Unicode: U+0048 (H)*/ + {.w_px = 8, .glyph_index = 3040}, /*Unicode: U+0049 (I)*/ + {.w_px = 8, .glyph_index = 3120}, /*Unicode: U+004a (J)*/ + {.w_px = 9, .glyph_index = 3200}, /*Unicode: U+004b (K)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+004c (L)*/ + {.w_px = 9, .glyph_index = 3380}, /*Unicode: U+004d (M)*/ + {.w_px = 8, .glyph_index = 3480}, /*Unicode: U+004e (N)*/ + {.w_px = 8, .glyph_index = 3560}, /*Unicode: U+004f (O)*/ + {.w_px = 8, .glyph_index = 3640}, /*Unicode: U+0050 (P)*/ + {.w_px = 8, .glyph_index = 3720}, /*Unicode: U+0051 (Q)*/ + {.w_px = 8, .glyph_index = 3800}, /*Unicode: U+0052 (R)*/ + {.w_px = 8, .glyph_index = 3880}, /*Unicode: U+0053 (S)*/ + {.w_px = 8, .glyph_index = 3960}, /*Unicode: U+0054 (T)*/ + {.w_px = 8, .glyph_index = 4040}, /*Unicode: U+0055 (U)*/ + {.w_px = 9, .glyph_index = 4120}, /*Unicode: U+0056 (V)*/ + {.w_px = 9, .glyph_index = 4220}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 4320}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 4420}, /*Unicode: U+0059 (Y)*/ + {.w_px = 8, .glyph_index = 4520}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 4600}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 4660}, /*Unicode: U+005c (\)*/ + {.w_px = 6, .glyph_index = 4740}, /*Unicode: U+005d (])*/ + {.w_px = 10, .glyph_index = 4800}, /*Unicode: U+005e (^)*/ + {.w_px = 10, .glyph_index = 4900}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 5000}, /*Unicode: U+0060 (`)*/ + {.w_px = 8, .glyph_index = 5040}, /*Unicode: U+0061 (a)*/ + {.w_px = 8, .glyph_index = 5120}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 5200}, /*Unicode: U+0063 (c)*/ + {.w_px = 8, .glyph_index = 5280}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 5360}, /*Unicode: U+0065 (e)*/ + {.w_px = 9, .glyph_index = 5460}, /*Unicode: U+0066 (f)*/ + {.w_px = 8, .glyph_index = 5560}, /*Unicode: U+0067 (g)*/ + {.w_px = 8, .glyph_index = 5640}, /*Unicode: U+0068 (h)*/ + {.w_px = 9, .glyph_index = 5720}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 5820}, /*Unicode: U+006a (j)*/ + {.w_px = 9, .glyph_index = 5900}, /*Unicode: U+006b (k)*/ + {.w_px = 8, .glyph_index = 6000}, /*Unicode: U+006c (l)*/ + {.w_px = 8, .glyph_index = 6080}, /*Unicode: U+006d (m)*/ + {.w_px = 8, .glyph_index = 6160}, /*Unicode: U+006e (n)*/ + {.w_px = 8, .glyph_index = 6240}, /*Unicode: U+006f (o)*/ + {.w_px = 8, .glyph_index = 6320}, /*Unicode: U+0070 (p)*/ + {.w_px = 8, .glyph_index = 6400}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 6480}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 6560}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 6640}, /*Unicode: U+0074 (t)*/ + {.w_px = 8, .glyph_index = 6720}, /*Unicode: U+0075 (u)*/ + {.w_px = 9, .glyph_index = 6800}, /*Unicode: U+0076 (v)*/ + {.w_px = 10, .glyph_index = 6900}, /*Unicode: U+0077 (w)*/ + {.w_px = 10, .glyph_index = 7000}, /*Unicode: U+0078 (x)*/ + {.w_px = 9, .glyph_index = 7100}, /*Unicode: U+0079 (y)*/ + {.w_px = 8, .glyph_index = 7200}, /*Unicode: U+007a (z)*/ + {.w_px = 7, .glyph_index = 7280}, /*Unicode: U+007b ({)*/ + {.w_px = 2, .glyph_index = 7360}, /*Unicode: U+007c (|)*/ + {.w_px = 8, .glyph_index = 7380}, /*Unicode: U+007d (})*/ + {.w_px = 9, .glyph_index = 7460}, /*Unicode: U+007e (~)*/ + +#elif USE_UBUNTU_MONO == 8 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 2, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 160}, /*Unicode: U+0022 (")*/ + {.w_px = 10, .glyph_index = 260}, /*Unicode: U+0023 (#)*/ + {.w_px = 8, .glyph_index = 460}, /*Unicode: U+0024 ($)*/ + {.w_px = 10, .glyph_index = 620}, /*Unicode: U+0025 (%)*/ + {.w_px = 10, .glyph_index = 820}, /*Unicode: U+0026 (&)*/ + {.w_px = 2, .glyph_index = 1020}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 1060}, /*Unicode: U+0028 (()*/ + {.w_px = 6, .glyph_index = 1180}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 1300}, /*Unicode: U+002a (*)*/ + {.w_px = 8, .glyph_index = 1480}, /*Unicode: U+002b (+)*/ + {.w_px = 4, .glyph_index = 1640}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 1720}, /*Unicode: U+002d (-)*/ + {.w_px = 4, .glyph_index = 1820}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1900}, /*Unicode: U+002f (/)*/ + {.w_px = 8, .glyph_index = 2060}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 2220}, /*Unicode: U+0031 (1)*/ + {.w_px = 8, .glyph_index = 2360}, /*Unicode: U+0032 (2)*/ + {.w_px = 8, .glyph_index = 2520}, /*Unicode: U+0033 (3)*/ + {.w_px = 8, .glyph_index = 2680}, /*Unicode: U+0034 (4)*/ + {.w_px = 8, .glyph_index = 2840}, /*Unicode: U+0035 (5)*/ + {.w_px = 8, .glyph_index = 3000}, /*Unicode: U+0036 (6)*/ + {.w_px = 7, .glyph_index = 3160}, /*Unicode: U+0037 (7)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+0038 (8)*/ + {.w_px = 8, .glyph_index = 3460}, /*Unicode: U+0039 (9)*/ + {.w_px = 4, .glyph_index = 3620}, /*Unicode: U+003a (:)*/ + {.w_px = 4, .glyph_index = 3700}, /*Unicode: U+003b (;)*/ + {.w_px = 9, .glyph_index = 3780}, /*Unicode: U+003c (<)*/ + {.w_px = 8, .glyph_index = 3960}, /*Unicode: U+003d (=)*/ + {.w_px = 8, .glyph_index = 4120}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 4280}, /*Unicode: U+003f (?)*/ + {.w_px = 9, .glyph_index = 4440}, /*Unicode: U+0040 (@)*/ + {.w_px = 10, .glyph_index = 4620}, /*Unicode: U+0041 (A)*/ + {.w_px = 8, .glyph_index = 4820}, /*Unicode: U+0042 (B)*/ + {.w_px = 8, .glyph_index = 4980}, /*Unicode: U+0043 (C)*/ + {.w_px = 8, .glyph_index = 5140}, /*Unicode: U+0044 (D)*/ + {.w_px = 8, .glyph_index = 5300}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 5460}, /*Unicode: U+0046 (F)*/ + {.w_px = 8, .glyph_index = 5620}, /*Unicode: U+0047 (G)*/ + {.w_px = 8, .glyph_index = 5780}, /*Unicode: U+0048 (H)*/ + {.w_px = 8, .glyph_index = 5940}, /*Unicode: U+0049 (I)*/ + {.w_px = 8, .glyph_index = 6100}, /*Unicode: U+004a (J)*/ + {.w_px = 9, .glyph_index = 6260}, /*Unicode: U+004b (K)*/ + {.w_px = 8, .glyph_index = 6440}, /*Unicode: U+004c (L)*/ + {.w_px = 9, .glyph_index = 6600}, /*Unicode: U+004d (M)*/ + {.w_px = 8, .glyph_index = 6780}, /*Unicode: U+004e (N)*/ + {.w_px = 8, .glyph_index = 6940}, /*Unicode: U+004f (O)*/ + {.w_px = 8, .glyph_index = 7100}, /*Unicode: U+0050 (P)*/ + {.w_px = 8, .glyph_index = 7260}, /*Unicode: U+0051 (Q)*/ + {.w_px = 8, .glyph_index = 7420}, /*Unicode: U+0052 (R)*/ + {.w_px = 8, .glyph_index = 7580}, /*Unicode: U+0053 (S)*/ + {.w_px = 8, .glyph_index = 7740}, /*Unicode: U+0054 (T)*/ + {.w_px = 8, .glyph_index = 7900}, /*Unicode: U+0055 (U)*/ + {.w_px = 9, .glyph_index = 8060}, /*Unicode: U+0056 (V)*/ + {.w_px = 9, .glyph_index = 8240}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 8420}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 8620}, /*Unicode: U+0059 (Y)*/ + {.w_px = 8, .glyph_index = 8820}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 8980}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 9100}, /*Unicode: U+005c (\)*/ + {.w_px = 6, .glyph_index = 9260}, /*Unicode: U+005d (])*/ + {.w_px = 10, .glyph_index = 9380}, /*Unicode: U+005e (^)*/ + {.w_px = 10, .glyph_index = 9580}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 9780}, /*Unicode: U+0060 (`)*/ + {.w_px = 8, .glyph_index = 9860}, /*Unicode: U+0061 (a)*/ + {.w_px = 8, .glyph_index = 10020}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 10180}, /*Unicode: U+0063 (c)*/ + {.w_px = 8, .glyph_index = 10340}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 10500}, /*Unicode: U+0065 (e)*/ + {.w_px = 9, .glyph_index = 10680}, /*Unicode: U+0066 (f)*/ + {.w_px = 8, .glyph_index = 10860}, /*Unicode: U+0067 (g)*/ + {.w_px = 8, .glyph_index = 11020}, /*Unicode: U+0068 (h)*/ + {.w_px = 9, .glyph_index = 11180}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 11360}, /*Unicode: U+006a (j)*/ + {.w_px = 9, .glyph_index = 11500}, /*Unicode: U+006b (k)*/ + {.w_px = 8, .glyph_index = 11680}, /*Unicode: U+006c (l)*/ + {.w_px = 8, .glyph_index = 11840}, /*Unicode: U+006d (m)*/ + {.w_px = 8, .glyph_index = 12000}, /*Unicode: U+006e (n)*/ + {.w_px = 8, .glyph_index = 12160}, /*Unicode: U+006f (o)*/ + {.w_px = 8, .glyph_index = 12320}, /*Unicode: U+0070 (p)*/ + {.w_px = 8, .glyph_index = 12480}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 12640}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 12780}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 12940}, /*Unicode: U+0074 (t)*/ + {.w_px = 8, .glyph_index = 13100}, /*Unicode: U+0075 (u)*/ + {.w_px = 9, .glyph_index = 13260}, /*Unicode: U+0076 (v)*/ + {.w_px = 10, .glyph_index = 13440}, /*Unicode: U+0077 (w)*/ + {.w_px = 10, .glyph_index = 13640}, /*Unicode: U+0078 (x)*/ + {.w_px = 9, .glyph_index = 13840}, /*Unicode: U+0079 (y)*/ + {.w_px = 8, .glyph_index = 14020}, /*Unicode: U+007a (z)*/ + {.w_px = 7, .glyph_index = 14180}, /*Unicode: U+007b ({)*/ + {.w_px = 2, .glyph_index = 14320}, /*Unicode: U+007c (|)*/ + {.w_px = 8, .glyph_index = 14360}, /*Unicode: U+007d (})*/ + {.w_px = 9, .glyph_index = 14520}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t ubuntu_mono = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = ubuntu_mono_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR), + .glyph_dsc = ubuntu_mono_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_UBUNTU_MONO == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_UBUNTU_MONO == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 10, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_UBUNTU_MONO*/ diff --git a/bdk/libs/lvgl/lv_hal/lv_hal.h b/bdk/libs/lvgl/lv_hal/lv_hal.h new file mode 100644 index 0000000..5ab28f2 --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal.h @@ -0,0 +1,40 @@ +/** + * @file hal.h + * + */ + +#ifndef HAL_H +#define HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_hal/lv_hal.mk b/bdk/libs/lvgl/lv_hal/lv_hal.mk new file mode 100644 index 0000000..83f4bf1 --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal.mk @@ -0,0 +1,8 @@ +CSRCS += lv_hal_disp.c +CSRCS += lv_hal_indev.c +CSRCS += lv_hal_tick.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal +VPATH += :$(LVGL_DIR)/lvgl/lv_hal + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal" diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_disp.c b/bdk/libs/lvgl/lv_hal/lv_hal_disp.c new file mode 100644 index 0000000..3be8b92 --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_disp.c @@ -0,0 +1,242 @@ + +/** + * @file hal_disp.c + * + * @description HAL layer for display driver + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_disp_t * active; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t * driver) +{ + driver->disp_fill = NULL; + driver->disp_map = NULL; + driver->disp_flush = NULL; + +#if USE_LV_GPU + driver->mem_blend = NULL; + driver->mem_fill = NULL; +#endif + +#if LV_VDB_SIZE + driver->vdb_wr = NULL; +#endif +} + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) +{ + lv_disp_t * node; + + node = lv_mem_alloc(sizeof(lv_disp_t)); + lv_mem_assert(node); + if(node == NULL) return NULL; + + memcpy(&node->driver, driver, sizeof(lv_disp_drv_t)); + node->next = NULL; + + /* Set first display as active by default */ + if(LV_GC_ROOT(_lv_disp_list) == NULL) { + LV_GC_ROOT(_lv_disp_list) = node; + active = node; + lv_obj_invalidate(lv_scr_act()); + } else { + ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next = node; + } + + return node; +} + + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp) +{ + active = disp; + lv_obj_invalidate(lv_scr_act()); +} + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void) +{ + return active; +} + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp) +{ + if(disp == NULL) { + return LV_GC_ROOT(_lv_disp_list); + } else { + if(((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next == NULL) return NULL; + else return ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next; + } +} + +/** + * Write the content of the internal buffer (VDB) to the display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + if(active == NULL) return; + if(active->driver.disp_fill != NULL) active->driver.disp_fill(x1, y1, x2, y2, color); +} + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p) +{ + if(active == NULL) return; + if(active->driver.disp_flush != NULL) { + + LV_LOG_TRACE("disp flush started"); + active->driver.disp_flush(x1, y1, x2, y2, color_p); + LV_LOG_TRACE("disp flush ready"); + + } else { + LV_LOG_WARN("disp flush function registered"); + } +} + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map) +{ + if(active == NULL) return; + if(active->driver.disp_map != NULL) active->driver.disp_map(x1, y1, x2, y2, color_map); +} + +#if USE_LV_GPU + +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa) +{ + if(active == NULL) return; + if(active->driver.mem_blend != NULL) active->driver.mem_blend(dest, src, length, opa); +} + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color) +{ + if(active == NULL) return; + if(active->driver.mem_fill != NULL) active->driver.mem_fill(dest, length, color); +} + +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void) +{ + if(active == NULL) return false; + if(active->driver.mem_blend) return true; + else return false; +} + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void) +{ + if(active == NULL) return false; + if(active->driver.mem_fill) return true; + else return false; +} + +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_disp.h b/bdk/libs/lvgl/lv_hal/lv_hal_disp.h new file mode 100644 index 0000000..95b7ab5 --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_disp.h @@ -0,0 +1,173 @@ +/** + * @file hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef HAL_DISP_H +#define HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_hal.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Display Driver structure to be registered by HAL + */ +typedef struct _disp_drv_t { + /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ + void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Fill an area with a color on the display*/ + void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + + /*Write pixel map (e.g. image) to the display*/ + void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Optional interface functions to use GPU*/ +#if USE_LV_GPU + /*Blend two memories using opacity (GPU only)*/ + void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + + /*Fill a memory with a color (GPU only)*/ + void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); +#endif + +#if LV_VDB_SIZE + /*Optional: Set a pixel in a buffer according to the requirements of the display*/ + void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#endif +} lv_disp_drv_t; + +typedef struct _disp_t { + lv_disp_drv_t driver; + struct _disp_t *next; +} lv_disp_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t *driver); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp); + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void); + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map); + +#if USE_LV_GPU +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void); + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void); +#endif +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_indev.c b/bdk/libs/lvgl/lv_hal/lv_hal_indev.c new file mode 100644 index 0000000..6083c3f --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_indev.c @@ -0,0 +1,135 @@ +/** + * @file hal_indev.c + * + * @description Input device HAL interface + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t * driver) +{ + driver->read = NULL; + driver->type = LV_INDEV_TYPE_NONE; + driver->user_data = NULL; +} + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver) +{ + lv_indev_t * node; + + node = lv_mem_alloc(sizeof(lv_indev_t)); + if(!node) return NULL; + + memset(node, 0, sizeof(lv_indev_t)); + memcpy(&node->driver, driver, sizeof(lv_indev_drv_t)); + + node->next = NULL; + node->proc.reset_query = 1; + node->cursor = NULL; + node->group = NULL; + node->btn_points = NULL; + + if(LV_GC_ROOT(_lv_indev_list) == NULL) { + LV_GC_ROOT(_lv_indev_list) = node; + } else { + lv_indev_t * last = LV_GC_ROOT(_lv_indev_list); + while(last->next) + last = last->next; + + last->next = node; + } + + return node; +} + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Give the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev) +{ + + if(indev == NULL) { + return LV_GC_ROOT(_lv_indev_list); + } else { + if(indev->next == NULL) return NULL; + else return indev->next; + } +} + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data) +{ + bool cont = false; + + memset(data, 0, sizeof(lv_indev_data_t)); + data->state = LV_INDEV_STATE_REL; + + if(indev->driver.read) { + data->user_data = indev->driver.user_data; + + LV_LOG_TRACE("idnev read started"); + cont = indev->driver.read(data); + LV_LOG_TRACE("idnev read finished"); + } else { + LV_LOG_WARN("indev function registered"); + } + + return cont; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_indev.h b/bdk/libs/lvgl/lv_hal/lv_hal_indev.h new file mode 100644 index 0000000..2355baa --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_indev.h @@ -0,0 +1,166 @@ +/** + * @file hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef HAL_INDEV_H +#define HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_hal.h" +#include +#include "../lv_misc/lv_area.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Possible input device types*/ +enum { + LV_INDEV_TYPE_NONE, /*Show uninitialized state*/ + LV_INDEV_TYPE_POINTER, /*Touch pad, mouse, external button*/ + LV_INDEV_TYPE_KEYPAD, /*Keypad or keyboard*/ + LV_INDEV_TYPE_BUTTON, /*External (hardware button) which is assinged to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/ +}; +typedef uint8_t lv_hal_indev_type_t; + +/*States for input devices*/ +enum { + LV_INDEV_STATE_REL = 0, + LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; + +/*Data type when an input device is read */ +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +/*Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct { + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ +} lv_indev_drv_t; + +struct _lv_obj_t; + +/*Run time data of input devices*/ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; + union { + struct { /*Pointer and button data*/ + lv_point_t act_point; + lv_point_t last_point; + lv_point_t vect; + lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/ + struct _lv_obj_t * act_obj; + struct _lv_obj_t * last_obj; + + /*Flags*/ + uint8_t drag_range_out :1; + uint8_t drag_in_prog :1; + uint8_t wait_unil_release :1; + }; + struct { /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + }; + }; + + uint32_t pr_timestamp; /*Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/ + + /*Flags*/ + uint8_t long_pr_sent :1; + uint8_t reset_query :1; + uint8_t disabled :1; +} lv_indev_proc_t; + +struct _lv_indev_t; + +typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t); + +struct _lv_obj_t; +struct _lv_group_t; + +/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/ +typedef struct _lv_indev_t { + lv_indev_drv_t driver; + lv_indev_proc_t proc; + lv_indev_feedback_t feedback; + uint32_t last_activity_time; + union { + struct _lv_obj_t *cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/ + struct _lv_group_t *group; /*Keypad destination group*/ + const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed here by the buttons*/ + + }; + struct _lv_indev_t *next; +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t *driver); + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev); + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_tick.c b/bdk/libs/lvgl/lv_hal/lv_hal_tick.c new file mode 100644 index 0000000..0310092 --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_tick.c @@ -0,0 +1,100 @@ +/** + * @file systick.c + * Provide access to the system tick with 1 millisecond resolution + */ + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_hal_tick.h" +#include + +#if LV_TICK_CUSTOM == 1 +#include LV_TICK_CUSTOM_INCLUDE +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static uint32_t sys_time = 0; +static volatile uint8_t tick_irq_flag; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period) +{ + tick_irq_flag = 0; + sys_time += tick_period; +} + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void) +{ +#if LV_TICK_CUSTOM == 0 + uint32_t result; + do { + tick_irq_flag = 1; + result = sys_time; + } while(!tick_irq_flag); /*'lv_tick_inc()' clears this flag which can be in an interrupt. Continue until make a non interrupted cycle */ + + return result; +#else + return LV_TICK_CUSTOM_SYS_TIME_EXPR; +#endif +} + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick) +{ + uint32_t act_time = lv_tick_get(); + + /*If there is no overflow in sys_time simple subtract*/ + if(act_time >= prev_tick) { + prev_tick = act_time - prev_tick; + } else { + prev_tick = UINT32_MAX - prev_tick + 1; + prev_tick += act_time; + } + + return prev_tick; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + diff --git a/bdk/libs/lvgl/lv_hal/lv_hal_tick.h b/bdk/libs/lvgl/lv_hal/lv_hal_tick.h new file mode 100644 index 0000000..af3d8ea --- /dev/null +++ b/bdk/libs/lvgl/lv_hal/lv_hal_tick.h @@ -0,0 +1,65 @@ +/** + * @file lv_hal_tick.h + * Provide access to the system tick with 1 millisecond resolution + */ + +#ifndef LV_HAL_TICK_H +#define LV_HAL_TICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period); + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void); + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_HAL_TICK_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_anim.c b/bdk/libs/lvgl/lv_misc/lv_anim.c new file mode 100644 index 0000000..578c556 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_anim.c @@ -0,0 +1,445 @@ +/** + * @file anim.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_anim.h" + +#if USE_LV_ANIMATION +#include +#include +#include "../lv_hal/lv_hal_tick.h" +#include "lv_task.h" +#include "lv_math.h" +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ +#define LV_ANIM_RESOLUTION 1024 +#define LV_ANIM_RES_SHIFT 10 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void anim_task(void * param); +static bool anim_ready_handler(lv_anim_t * a); + +/********************** + * STATIC VARIABLES + **********************/ +static uint32_t last_task_run; +static bool anim_list_changed; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t)); + last_task_run = lv_tick_get(); + lv_task_create(anim_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL); +} + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p) +{ + LV_LOG_TRACE("animation create started") + /* Do not let two animations for the same 'var' with the same 'fp'*/ + if(anim_p->fp != NULL) lv_anim_del(anim_p->var, anim_p->fp); /*fp == NULL would delete all animations of var*/ + + /*Add the new animation to the animation linked list*/ + lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll)); + lv_mem_assert(new_anim); + if(new_anim == NULL) return; + + /*Initialize the animation descriptor*/ + anim_p->playback_now = 0; + memcpy(new_anim, anim_p, sizeof(lv_anim_t)); + + /*Set the start value*/ + if(new_anim->fp != NULL) new_anim->fp(new_anim->var, new_anim->start); + + /* Creating an animation changed the linked list. + * It's important if it happens in a ready callback. (see `anim_task`)*/ + anim_list_changed = true; + + LV_LOG_TRACE("animation created") +} + +/** + * Delete an animation for a variable with a given animator function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to delete all animations of 'var' + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp) +{ + lv_anim_t * a; + lv_anim_t * a_next; + bool del = false; + a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + while(a != NULL) { + /*'a' might be deleted, so get the next object while 'a' is valid*/ + a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + + if(a->var == var && (a->fp == fp || fp == NULL)) { + lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + lv_mem_free(a); + anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in the linked list*/ + del = true; + } + + a = a_next; + } + + return del; +} + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void) +{ + uint16_t cnt = 0; + lv_anim_t * a; + LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++; + + return cnt++; +} + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end) +{ + int32_t d = LV_MATH_ABS((int32_t) start - end); + uint32_t time = (int32_t)((int32_t)(d * 1000) / speed); + + if(time > UINT16_MAX) time = UINT16_MAX; + + if(time == 0) { + time++; + } + + return time; +} + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint16_t step; + if(a->time == a->act_time) step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/ + else step = (a->act_time * LV_ANIM_RESOLUTION) / a->time; + + /* Get the new value which will be proportional to `step` + * and the `start` and `end` values*/ + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> LV_ANIM_RES_SHIFT; + new_value += a->start; + + return new_value; +} + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 1, 1, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 1023, 1023, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 100, 924, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 600, 1300, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t diff = (a->end - a->start); + + /*3 bounces has 5 parts: 3 down and 2 up. One part is t / 5 long*/ + + if(t < 408){ + /*Go down*/ + t = (t * 2500) >> 10; /*[0..1024] range*/ + } + else if(t >= 408 && t < 614) { + /*First bounce back*/ + t -= 408; + t = t * 5; /*to [0..1024] range*/ + t = 1024 - t; + diff = diff / 6; + } + else if(t >= 614 && t < 819) { + /*Fall back*/ + t -= 614; + t = t * 5; /*to [0..1024] range*/ + diff = diff / 6; + } + else if(t >= 819 && t < 921) { + /*Second bounce back*/ + t -= 819; + t = t * 10; /*to [0..1024] range*/ + t = 1024 - t; + diff = diff / 16; + } + else if(t >= 921 && t <= 1024) { + /*Fall back*/ + t -= 921; + t = t * 10; /*to [0..1024] range*/ + diff = diff / 16; + } + + if(t > 1024) t = 1024; + + int32_t step = lv_bezier3(t, 1024, 1024, 800, 0); + + int32_t new_value; + + new_value = (int32_t) step * diff; + new_value = new_value >> 10; + new_value = a->end - new_value; + + + return new_value; +} + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t * a) +{ + if(a->act_time >= a->time) return a->end; + else return a->start; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Periodically handle the animations. + * @param param unused + */ +static void anim_task(void * param) +{ + (void)param; + + lv_anim_t * a; + LL_READ(LV_GC_ROOT(_lv_anim_ll), a) { + a->has_run = 0; + } + + uint32_t elaps = lv_tick_elaps(last_task_run); + a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + + while(a != NULL) { + /*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete happened in `anim_ready_handler` + * which could make this linked list reading corrupt because the list is changed meanwhile + */ + anim_list_changed = false; + + if(!a->has_run) { + a->has_run = 1; /*The list readying might be reseted so need to know which anim has run already*/ + a->act_time += elaps; + if(a->act_time >= 0) { + if(a->act_time > a->time) a->act_time = a->time; + + int32_t new_value; + new_value = a->path(a); + + if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/ + + /*If the time is elapsed the animation is ready*/ + if(a->act_time >= a->time) { + anim_ready_handler(a); + } + } + } + + /* If the linked list changed due to anim. delete then it's not safe to continue + * the reading of the list from here -> start from the head*/ + if(anim_list_changed) a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + else a = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + } + + last_task_run = lv_tick_get(); +} + +/** + * Called when an animation is ready to do the necessary thinks + * e.g. repeat, play back, delete etc. + * @param a pointer to an animation descriptor + * @return true: animation delete occurred nnd the `LV_GC_ROOT(_lv_anim_ll)` has changed + * */ +static bool anim_ready_handler(lv_anim_t * a) +{ + + /*Delete the animation if + * - no repeat and no play back (simple one shot animation) + * - no repeat, play back is enabled and play back is ready */ + if((a->repeat == 0 && a->playback == 0) || + (a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) { + void (*cb)(void *) = a->end_cb; + void * p = a->var; + lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + lv_mem_free(a); + anim_list_changed = true; + + /* Call the callback function at the end*/ + /* Check if an animation is deleted in the cb function + * if yes then the caller function has to know this*/ + if(cb != NULL) cb(p); + } + /*If the animation is not deleted then restart it*/ + else { + a->act_time = - a->repeat_pause; /*Restart the animation*/ + /*Swap the start and end values in play back mode*/ + if(a->playback != 0) { + /*If now turning back use the 'playback_pause*/ + if(a->playback_now == 0) a->act_time = - a->playback_pause; + + /*Toggle the play back state*/ + a->playback_now = a->playback_now == 0 ? 1 : 0; + /*Swap the start and end values*/ + int32_t tmp; + tmp = a->start; + a->start = a->end; + a->end = tmp; + } + } + + return anim_list_changed; +} +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_anim.h b/bdk/libs/lvgl/lv_misc/lv_anim.h new file mode 100644 index 0000000..6625ae2 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_anim.h @@ -0,0 +1,176 @@ +/** + * @file anim.h + * + */ + +#ifndef ANIM_H +#define ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ANIMATION + +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_t; + +typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*); + +typedef void (*lv_anim_fp_t)(void *, int32_t); +typedef void (*lv_anim_cb_t)(void *); + +typedef struct _lv_anim_t +{ + void * var; /*Variable to animate*/ + lv_anim_fp_t fp; /*Animator function*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready*/ + lv_anim_path_t path; /*An array with the steps of animations*/ + int32_t start; /*Start value*/ + int32_t end; /*End value*/ + uint16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ + /*Animation system use these - user shouldn't set*/ + uint8_t playback_now :1; /*Play back is in progress*/ + uint32_t has_run :1; /*Indicates the animation has run it this round*/ +} lv_anim_t; + +/*Example initialization +lv_anim_t a; +a.var = obj; +a.start = lv_obj_get_height(obj); +a.end = new_height; +a.fp = (lv_anim_fp_t)lv_obj_set_height; +a.path = lv_anim_path_linear; +a.end_cb = NULL; +a.act_time = 0; +a.time = 200; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +lv_anim_create(&a); + */ +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void); + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p); + +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp); + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void); + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t *a); + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t *a); + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t *a); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ANIMATION == 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_H*/ + diff --git a/bdk/libs/lvgl/lv_misc/lv_area.c b/bdk/libs/lvgl/lv_misc/lv_area.c new file mode 100644 index 0000000..f340690 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_area.c @@ -0,0 +1,200 @@ +/** + * @file lv_area.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_area.h" +#include "lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2) +{ + area_p->x1 = x1; + area_p->y1 = y1; + area_p->x2 = x2; + area_p->y2 = y2; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w) +{ + area_p->x2 = area_p->x1 + w - 1; +} + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h) +{ + area_p->y2 = area_p->y1 + h - 1; +} + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y) +{ + lv_coord_t w = lv_area_get_width(area_p); + lv_coord_t h = lv_area_get_height(area_p); + area_p->x1 = x; + area_p->y1 = y; + lv_area_set_width(area_p, w); + lv_area_set_height(area_p, h); +} + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p) +{ + uint32_t size; + + size = (uint32_t)(area_p->x2 - area_p->x1 + 1) * + (area_p->y2 - area_p->y1 + 1); + + return size; +} + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + /* Get the smaller area from 'a1_p' and 'a2_p' */ + res_p->x1 = LV_MATH_MAX(a1_p->x1, a2_p->x1); + res_p->y1 = LV_MATH_MAX(a1_p->y1, a2_p->y1); + res_p->x2 = LV_MATH_MIN(a1_p->x2, a2_p->x2); + res_p->y2 = LV_MATH_MIN(a1_p->y2, a2_p->y2); + + /*If x1 or y1 greater then x2 or y2 then the areas union is empty*/ + bool union_ok = true; + if((res_p->x1 > res_p->x2) || + (res_p->y1 > res_p->y2)) { + union_ok = false; + } + + return union_ok; +} +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + a_res_p->x1 = LV_MATH_MIN(a1_p->x1, a2_p->x1); + a_res_p->y1 = LV_MATH_MIN(a1_p->y1, a2_p->y1); + a_res_p->x2 = LV_MATH_MAX(a1_p->x2, a2_p->x2); + a_res_p->y2 = LV_MATH_MAX(a1_p->y2, a2_p->y2); +} + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p) +{ + bool is_on = false; + + if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) && + ((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) { + is_on = true; + } + + return is_on; +} + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + if((a1_p->x1 <= a2_p->x2) && + (a1_p->x2 >= a2_p->x1) && + (a1_p->y1 <= a2_p->y2) && + (a1_p->y2 >= a2_p->y1)) { + return true; + } else { + return false; + } + +} + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be in 'aholder_p' + * @param aholder pointer to an area which could involve 'ain_p' + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p) +{ + bool is_in = false; + + if(ain_p->x1 >= aholder_p->x1 && + ain_p->y1 >= aholder_p->y1 && + ain_p->x2 <= aholder_p->x2 && + ain_p->y2 <= aholder_p->y2) { + is_in = true; + } + + return is_in; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_misc/lv_area.h b/bdk/libs/lvgl/lv_misc/lv_area.h new file mode 100644 index 0000000..63ea059 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_area.h @@ -0,0 +1,168 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */ +#define LV_COORD_MIN (-16384) + +/********************** + * TYPEDEFS + **********************/ +typedef int16_t lv_coord_t; + +typedef struct +{ + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct +{ + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2); + +/** + * Copy an area + * @param dest pointer to the destination area + * @param src pointer to the source area + */ +inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) +{ + memcpy(dest, src, sizeof(lv_area_t)); +} + +/** + * Get the width of an area + * @param area_p pointer to an area + * @return the width of the area (if x1 == x2 -> width = 1) + */ +static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p) +{ + return area_p->x2 - area_p->x1 + 1; +} + +/** + * Get the height of an area + * @param area_p pointer to an area + * @return the height of the area (if y1 == y2 -> height = 1) + */ +static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p) +{ + return area_p->y2 - area_p->y1 + 1; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w); + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p); + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored her + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be on aholder_p + * @param aholder pointer to an area which could involve ain_p + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_circ.c b/bdk/libs/lvgl/lv_misc/lv_circ.c new file mode 100644 index 0000000..d89d833 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_circ.c @@ -0,0 +1,79 @@ +/** + * @file lv_circ.c + * Circle drawing algorithm (with Bresenham) + * Only a 1/8 circle is calculated. Use CIRC_OCT1_X, CIRC_OCT1_Y macros to get + * the other octets. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_circ.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius) +{ + c->x = radius; + c->y = 0; + *tmp = 1 - radius; +} + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c) +{ + return c->y <= c->x ? true : false; +} + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp) +{ + c->y++; + + if(*tmp <= 0) { + (*tmp) += 2 * c->y + 1; // Change in decision criterion for y -> y+1 + } else { + c->x--; + (*tmp) += 2 * (c->y - c->x) + 1; // Change for y -> y+1, x -> x-1 + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_misc/lv_circ.h b/bdk/libs/lvgl/lv_misc/lv_circ.h new file mode 100644 index 0000000..bc1c1dd --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_circ.h @@ -0,0 +1,80 @@ +/** + * @file lv_circ.h + * + */ + +#ifndef LV_CIRC_H +#define LV_CIRC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_area.h" +#include + +/********************* + * DEFINES + *********************/ +#define LV_CIRC_OCT1_X(p) (p.x) +#define LV_CIRC_OCT1_Y(p) (p.y) +#define LV_CIRC_OCT2_X(p) (p.y) +#define LV_CIRC_OCT2_Y(p) (p.x) +#define LV_CIRC_OCT3_X(p) (-p.y) +#define LV_CIRC_OCT3_Y(p) (p.x) +#define LV_CIRC_OCT4_X(p) (-p.x) +#define LV_CIRC_OCT4_Y(p) (p.y) +#define LV_CIRC_OCT5_X(p) (-p.x) +#define LV_CIRC_OCT5_Y(p) (-p.y) +#define LV_CIRC_OCT6_X(p) (-p.y) +#define LV_CIRC_OCT6_Y(p) (-p.x) +#define LV_CIRC_OCT7_X(p) (p.y) +#define LV_CIRC_OCT7_Y(p) (-p.x) +#define LV_CIRC_OCT8_X(p) (p.x) +#define LV_CIRC_OCT8_Y(p) (-p.y) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c); + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_color.c b/bdk/libs/lvgl/lv_misc/lv_color.c new file mode 100644 index 0000000..8c12193 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_color.c @@ -0,0 +1,167 @@ +/* + * 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 . + */ + +/** + * @file lv_color.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_color.h" + +/********************* + * DEFINES + *********************/ + +#define HUE_DEGREE 512 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val) +{ + uint8_t r, g, b; + + uint32_t h = (hue * 360 * HUE_DEGREE -1) / 360; + uint32_t s = sat * 255 / 100; + uint32_t v = val * 255 / 100; + uint32_t p = (256 * v - s * v) / 256; + uint32_t region = h / (60 * 512); + + if(sat == 0) + return LV_COLOR_MAKE(v, v, v); + + if (region & 1) + { + uint32_t q = (256 * 60 * HUE_DEGREE * v - h * s * v + 60 * HUE_DEGREE * s * v * region) / + (256 * 60 * HUE_DEGREE); + + switch (region) + { + case 1: + r = q; + g = v; + b = p; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 5: + default: + r = v; + g = p; + b = q; + break; + } + } + else + { + uint32_t t = (256 * 60 * HUE_DEGREE * v + h * s * v - 60 * HUE_DEGREE * s * v * (region + 1)) / + (256 * 60 * HUE_DEGREE); + + switch (region) + { + case 0: + r = v; + g = t; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 4: + default: + r = t; + g = p; + b = v; + break; + } + } + + return LV_COLOR_MAKE(r, g, b); +} + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b) +{ + lv_color_hsv_t hsv; + uint8_t rgbMin, rgbMax; + + rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b); + rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b); + + hsv.v = rgbMax; + if(hsv.v == 0) { + hsv.h = 0; + hsv.s = 0; + return hsv; + } + + hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v; + if(hsv.s == 0) { + hsv.h = 0; + return hsv; + } + + if(rgbMax == r) + hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin); + else if(rgbMax == g) + hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin); + else + hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin); + + return hsv; +} diff --git a/bdk/libs/lvgl/lv_misc/lv_color.h b/bdk/libs/lvgl/lv_misc/lv_color.h new file mode 100644 index 0000000..3459b63 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_color.h @@ -0,0 +1,455 @@ +/* + * 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 . + */ + +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +/*Error checking*/ +#if LV_COLOR_DEPTH == 24 +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#endif + +#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0 +#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h" +#endif + +#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0 +#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h" +#endif + + +#include + +/********************* + * DEFINES + *********************/ +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80) +#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00) + +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; + +#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ + +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_SIZE 16 +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_SIZE 32 +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef union +{ + uint8_t blue :1; + uint8_t green :1; + uint8_t red :1; + uint8_t full :1; +} lv_color1_t; + +typedef union +{ + struct + { + uint8_t blue :2; + uint8_t green :3; + uint8_t red :3; + }; + uint8_t full; +} lv_color8_t; + +typedef union +{ + struct + { +#if LV_COLOR_16_SWAP == 0 + uint16_t blue :5; + uint16_t green :6; + uint16_t red :5; +#else + uint16_t green_h :3; + uint16_t red :5; + uint16_t blue :5; + uint16_t green_l :3; +#endif + }; + uint16_t full; +} lv_color16_t; + +typedef union +{ + struct + { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +#if LV_COLOR_DEPTH == 1 +typedef uint8_t lv_color_int_t; +typedef lv_color1_t lv_color_t; +#elif LV_COLOR_DEPTH == 8 +typedef uint8_t lv_color_int_t; +typedef lv_color8_t lv_color_t; +#elif LV_COLOR_DEPTH == 16 +typedef uint16_t lv_color_int_t; +typedef lv_color16_t lv_color_t; +#elif LV_COLOR_DEPTH == 32 +typedef uint32_t lv_color_int_t; +typedef lv_color32_t lv_color_t; +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +typedef uint8_t lv_opa_t; + +typedef struct +{ + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*In color conversations: + * - When converting to bigger color type the LSB weight of 1 LSB is calculated + * E.g. 16 bit Red has 5 bits + * 8 bit Red has 2 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 2 bits + * 16 bit Red has 5 bits + * ---------------------- + * Shift right with 5 - 3 = 2 + */ + +static inline uint8_t lv_color_to1(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + return color.full; +#elif LV_COLOR_DEPTH == 8 + if((color.red & 0x4) || + (color.green & 0x4) || + (color.blue & 0x2)) { + return 1; + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + if((color.red & 0x10) || + (color.green & 0x20) || + (color.blue & 0x10)) { + return 1; +# else + if((color.red & 0x10) || + (color.green_h & 0x20) || + (color.blue & 0x10)) { + return 1; +# endif + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((color.red & 0x80) || + (color.green & 0x80) || + (color.blue & 0x80)) { + return 1; + } else { + return 0; + } +#endif +} + +static inline uint8_t lv_color_to8(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFF; +#elif LV_COLOR_DEPTH == 8 + return color.full; +#elif LV_COLOR_DEPTH == 16 + +# if LV_COLOR_16_SWAP == 0 + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green >> 3; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# else + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green_h; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + ret.red = color.red >> 5; /* 8 - 3 = 5*/ + ret.green = color.green >> 5; /* 8 - 3 = 5*/ + ret.blue = color.blue >> 6; /* 8 - 2 = 6*/ + return ret.full; +#endif +} + +static inline uint16_t lv_color_to16(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ +# else + ret.red = color.red * 4; + uint8_t g_tmp = color.green * 9; + ret.green_h = (g_tmp & 0x1F) >> 3; + ret.green_l = g_tmp & 0x07; + ret.blue = color.blue * 10; +# endif + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red >> 3; /* 8 - 5 = 3*/ + ret.green = color.green >> 2; /* 8 - 6 = 2*/ + ret.blue = color.blue >> 3; /* 8 - 5 = 3*/ +# else + ret.red = color.red >> 3; + ret.green_h = (color.green & 0xE0) >> 5; + ret.green_l = (color.green & 0x1C) >> 2; + ret.blue = color.blue >> 3; +# endif + return ret.full; +#endif +} + +static inline uint32_t lv_color_to32(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + ret.alpha = 0xFF; + return ret.full; +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# else + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +static inline lv_color_t lv_color_mix(const lv_color_t c1, const lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 && LV_COLOR_DEPTH != 32 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + ret.red = (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP + /*If swapped Green is in 2 parts*/ + uint16_t g_1 = (c1.green_h << 3) + c1.green_l; + uint16_t g_2 = (c2.green_h << 3) + c2.green_l; + uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8; + ret.green_h = g_out >> 3; + ret.green_l = g_out & 0x7; +# else + ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8; +# endif + ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8; +#else +# if LV_COLOR_DEPTH == 32 + uint32_t rb = (((c1.full & 0x00FF00FF) * mix) + ((c2.full & 0x00FF00FF) * (255 - mix))) >> 8; + uint32_t g = (((((c1.full & 0x0000FF00) >> 8) * mix) + (((c2.full & 0x0000FF00) >> 8) * (255 - mix))) >> 8) << 8; + ret.full = 0xFF000000 | (0x00FF00FF & rb) | (0x0000FF00 & g); +# else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +# endif +#endif + + return ret; +} + +/** + * Get the brightness of a color + * @param color a color + * @return the brightness [0..255] + */ +static inline uint8_t lv_color_brightness(lv_color_t color) +{ + lv_color32_t c32; + c32.full = lv_color_to32(color); + uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green; + return (uint16_t) bright >> 3; +} + +/* The most simple macro to create a color from R,G and B values + * The order of bit field is different on Big-endian and Little-endian machines*/ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}}) +# else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}}) +# endif +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ +#endif +#else +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}}) +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/ +#endif +#endif + +#if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set. +#define LV_COLOR_HEX(c) ((lv_color_t){.full = (c | 0xFF000000)}) +#else +#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)c >> 16) & 0xFF), \ + ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ + ((uint32_t) c & 0xFF)) +#endif + +/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ + ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ + ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) + + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val); + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_COLOR*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_font.c b/bdk/libs/lvgl/lv_misc/lv_font.c new file mode 100644 index 0000000..0aa7fe2 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_font.c @@ -0,0 +1,269 @@ +/** + * @file lv_font.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_font.h" +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void) +{ + lv_font_builtin_init(); +} + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t * child, lv_font_t * parent) +{ + if(parent == NULL) return; + + while(parent->next_page != NULL) { + parent = parent->next_page; /*Got to the last page and add the new font there*/ + } + + parent->next_page = child; + +} + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent) +{ + if(parent == NULL) return; + if(child == NULL) return; + + while(parent->next_page != child) { + parent = parent->next_page; /*Got to the last page and add the new font there*/ + } + + parent->next_page = child->next_page; +} + + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) { + /*Glyph found*/ + if(font_i->monospace) return true; + return false; + } + + font_i = font_i->next_page; + } + + return 0; +} + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + while(font_i != NULL) { + const uint8_t * bitmap = font_i->get_bitmap(font_i, letter); + if(bitmap) return bitmap; + + font_i = font_i->next_page; + } + + return NULL; +} + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) { + /*Glyph found*/ + uint8_t m = font_i->monospace; + if(m) w = m; + return w; + } + + font_i = font_i->next_page; + } + + return 0; + +} + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) return w; + + font_i = font_i->next_page; + } + + return 0; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter) +{ + const lv_font_t * font_i = font; + while(font_i != NULL) { + if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) { + return font_i->bpp; + } + font_i = font_i->next_page; + } + + return 0; + +} + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL; + + uint32_t index = (unicode_letter - font->unicode_first); + return &font->glyph_bitmap[font->glyph_dsc[index].glyph_index]; +} + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL; + + uint32_t i; + for(i = 0; font->unicode_list[i] != 0; i++) { + if(font->unicode_list[i] == unicode_letter) { + return &font->glyph_bitmap[font->glyph_dsc[i].glyph_index]; + } + } + + return NULL; +} + +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) { + return -1; + } + + uint32_t index = (unicode_letter - font->unicode_first); + return font->glyph_dsc[index].w_px; +} + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return -1; + + uint32_t i; + for(i = 0; font->unicode_list[i] != 0; i++) { + if(font->unicode_list[i] == unicode_letter) { + return font->glyph_dsc[i].w_px; + } + } + + return -1; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_misc/lv_font.h b/bdk/libs/lvgl/lv_misc/lv_font.h new file mode 100644 index 0000000..047de22 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_font.h @@ -0,0 +1,191 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include + +#include "lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t w_px :8; + uint32_t glyph_index :24; +} lv_font_glyph_dsc_t; + +typedef struct +{ + uint32_t unicode :21; + uint32_t glyph_dsc_index :11; +} lv_font_unicode_map_t; + +typedef struct _lv_font_struct +{ + uint32_t unicode_first; + uint32_t unicode_last; + const uint8_t * glyph_bitmap; + const lv_font_glyph_dsc_t * glyph_dsc; + const uint32_t * unicode_list; + const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/ + int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/ + struct _lv_font_struct * next_page; /*Pointer to a font extension*/ + uint32_t h_px :8; + uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/ + uint32_t monospace :8; /*Fix width (0: normal width)*/ + uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/ +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void); + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t *child, lv_font_t *parent); + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent); + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter); + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter); + + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the height of a font + * @param font_p pointer to a font + * @return the height of a font + */ +static inline uint8_t lv_font_get_height(const lv_font_t * font_p) +{ + return font_p->h_px; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter); +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter); + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name; + + +/********************** + * ADD BUILT IN FONTS + **********************/ +#include "../lv_fonts/lv_font_builtin.h" + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_FONT*/ + diff --git a/bdk/libs/lvgl/lv_misc/lv_fs.c b/bdk/libs/lvgl/lv_misc/lv_fs.c new file mode 100644 index 0000000..1828e39 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_fs.c @@ -0,0 +1,627 @@ +/** + * @file lv_fs.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_fs.h" +#if USE_LV_FILESYSTEM + +#include "lv_ll.h" +#include +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ + +/* "free" is used as a function pointer (in lv_fs_drv_t). + * We must make sure "free" was not defined to a platform specific + * free function, otherwise compilation would fail. + */ +#ifdef free +#undef free +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static const char * lv_fs_get_real_path(const char * path); +static lv_fs_drv_t * lv_fs_get_drv(char letter); + + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t)); +} + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter) +{ + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(drv == NULL) return false; /*An unknown driver in not ready*/ + + if(drv->ready == NULL) return true; /*Assume the driver is always ready if no handler provided*/ + + return drv->ready(); +} + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode) +{ + file_p->drv = NULL; + file_p->file_d = NULL; + + if(path == NULL) return LV_FS_RES_INV_PARAM; + + char letter = path[0]; + + file_p->drv = lv_fs_get_drv(letter); + + if(file_p->drv == NULL) { + file_p->file_d = NULL; + return LV_FS_RES_NOT_EX; + } + + if(file_p->drv->ready != NULL) { + if(file_p->drv->ready() == false) { + file_p->drv = NULL; + file_p->file_d = NULL; + return LV_FS_RES_HW_ERR; + } + } + + file_p->file_d = lv_mem_alloc(file_p->drv->file_size); + lv_mem_assert(file_p->file_d); + if(file_p->file_d == NULL) { + file_p->drv = NULL; + return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + } + + if(file_p->drv->open == NULL) { + return LV_FS_RES_NOT_IMP; + } + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode); + + if(res != LV_FS_RES_OK) { + lv_mem_free(file_p->file_d); + file_p->file_d = NULL; + file_p->drv = NULL; + } + + return res; +} + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->close == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->close(file_p->file_d); + + lv_mem_free(file_p->file_d); /*Clean up*/ + file_p->file_d = NULL; + file_p->drv = NULL; + file_p->file_d = NULL; + + return res; +} + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove(const char * path) +{ + if(path == NULL) return LV_FS_RES_INV_PARAM; + lv_fs_drv_t * drv = NULL; + + char letter = path[0]; + + drv = lv_fs_get_drv(letter); + if(drv == NULL) return LV_FS_RES_NOT_EX; + if(drv->ready != NULL) { + if(drv->ready() == false) return LV_FS_RES_HW_ERR; + } + + if(drv->remove == NULL) return LV_FS_RES_NOT_IMP; + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = drv->remove(real_path); + + return res; +} + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br) +{ + if(br != NULL) *br = 0; + if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM; + if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP; + + uint32_t br_tmp = 0; + lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp); + if(br != NULL) *br = br_tmp; + + return res; +} + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw) +{ + if(bw != NULL) *bw = 0; + + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->write == NULL) { + return LV_FS_RES_NOT_IMP; + } + + uint32_t bw_tmp = 0; + lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp); + if(bw != NULL) *bw = bw_tmp; + + return res; +} + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->seek == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos); + + return res; +} + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos) +{ + if(file_p->drv == NULL) { + pos = 0; + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->tell == NULL) { + pos = 0; + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos); + + return res; +} + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->tell == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->trunc(file_p->file_d); + + return res; +} +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP; + + + if(size == NULL) return LV_FS_RES_INV_PARAM; + + lv_fs_res_t res = file_p->drv->size(file_p->file_d, size); + + return res; +} + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname) +{ + if(!oldname || !newname) return LV_FS_RES_INV_PARAM; + + char letter = oldname[0]; + + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(!drv) { + return LV_FS_RES_NOT_EX; + } + + if(drv->ready != NULL) { + if(drv->ready() == false) { + return LV_FS_RES_HW_ERR; + } + } + + if(drv->rename == NULL) return LV_FS_RES_NOT_IMP; + + const char * old_real = lv_fs_get_real_path(oldname); + const char * new_real = lv_fs_get_real_path(newname); + lv_fs_res_t res = drv->rename(old_real, new_real); + + return res; +} + + +/** + * Initialize a 'fs_read_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) +{ + if(path == NULL) return LV_FS_RES_INV_PARAM; + + char letter = path[0]; + + rddir_p->drv = lv_fs_get_drv(letter); + + if(rddir_p->drv == NULL) { + rddir_p->dir_d = NULL; + return LV_FS_RES_NOT_EX; + } + + rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size); + lv_mem_assert(rddir_p->dir_d); + if(rddir_p->dir_d == NULL) { + rddir_p->dir_d = NULL; + return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + } + + if(rddir_p->drv->dir_open == NULL) { + return LV_FS_RES_NOT_IMP; + } + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path); + + return res; +} + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn) +{ + if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) { + fn[0] = '\0'; + return LV_FS_RES_INV_PARAM; + } + + if(rddir_p->drv->dir_read == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn); + + return res; +} + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p) +{ + if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) { + return LV_FS_RES_INV_PARAM; + } + + lv_fs_res_t res; + + if(rddir_p->drv->dir_close == NULL) { + res = LV_FS_RES_NOT_IMP; + } else { + res = rddir_p->drv->dir_close(rddir_p->dir_d); + } + + lv_mem_free(rddir_p->dir_d); /*Clean up*/ + rddir_p->dir_d = NULL; + rddir_p->drv = NULL; + rddir_p->dir_d = NULL; + + return res; +} + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free(char letter, uint32_t * total_p, uint32_t * free_p) +{ + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + lv_fs_res_t res; + + if(drv->free == NULL) { + res = LV_FS_RES_NOT_IMP; + } else { + uint32_t total_tmp = 0; + uint32_t free_tmp = 0; + res = drv->free(&total_tmp, &free_tmp); + + if(total_p != NULL) *total_p = total_tmp; + if(free_p != NULL) *free_p = free_tmp; + } + + return res; +} + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p) +{ + /*Save the new driver*/ + lv_fs_drv_t * new_drv; + new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll)); + lv_mem_assert(new_drv); + if(new_drv == NULL) return; + + memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t)); +} + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf) +{ + lv_fs_drv_t * drv; + uint8_t i = 0; + + LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { + buf[i] = drv->letter; + i++; + } + + buf[i] = '\0'; + + return buf; +} + + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn) +{ + uint16_t i; + for(i = strlen(fn); i > 0; i --) { + if(fn[i] == '.') { + return &fn[i + 1]; + } else if(fn[i] == '/' || fn[i] == '\\') { + return ""; /*No extension if a '\' or '/' found*/ + } + } + + return ""; /*Empty string if no '.' in the file name. */ +} + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path) +{ + uint16_t len = strlen(path); + if(len == 0) return path; + + len --; /*Go before the trailing '\0'*/ + + /*Ignore trailing '/' or '\'*/ + while(path[len] == '/' || path[len] == '\\') { + path[len] = '\0'; + if(len > 0) len --; + else return path; + } + + uint16_t i; + for(i = len; i > 0; i --) { + if(path[i] == '/' || path[i] == '\\') break; + } + + if(i > 0) path[i] = '\0'; + + return path; +} + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param path a character sting with the path to search in + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path) +{ + uint16_t len = strlen(path); + if(len == 0) return path; + + len --; /*Go before the trailing '\0'*/ + + /*Ignore trailing '/' or '\'*/ + while(path[len] == '/' || path[len] == '\\') { + if(len > 0) len --; + else return path; + } + + uint16_t i; + for(i = len; i > 0; i --) { + if(path[i] == '/' || path[i] == '\\') break; + } + + /*No '/' or '\' in the path so return with path itself*/ + if(i == 0) return path; + + return &path[i + 1]; +} +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Leave the driver letters and / or \ letters from beginning of the path + * @param path path string (E.g. S:/folder/file.txt) + * @return pointer to the beginning of the real path (E.g. folder/file.txt) + */ +static const char * lv_fs_get_real_path(const char * path) +{ + /* Example path: "S:/folder/file.txt" + * Leave the letter and the : / \ characters*/ + + path ++; /*Ignore the driver letter*/ + + while(*path != '\0') { + if(*path == ':' || *path == '\\' || *path == '/') { + path ++; + } else { + break; + } + } + + return path; +} + +/** + * Give a pointer to a driver from its letter + * @param letter the driver letter + * @return pointer to a driver or NULL if not found + */ +static lv_fs_drv_t * lv_fs_get_drv(char letter) +{ + lv_fs_drv_t * drv; + + LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { + if(drv->letter == letter) { + return drv; + } + } + + return NULL; +} + +#endif /*USE_LV_FILESYSTEM*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_fs.h b/bdk/libs/lvgl/lv_misc/lv_fs.h new file mode 100644 index 0000000..1eb2bfa --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_fs.h @@ -0,0 +1,276 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_FS_RES_OK = 0, + LV_FS_RES_HW_ERR, /*Low level hardware error*/ + LV_FS_RES_FS_ERR, /*Error in the file system structure */ + LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/ + LV_FS_RES_FULL, /*Disk full*/ + LV_FS_RES_LOCKED, /*The file is already opened*/ + LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/ + LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/ + LV_FS_RES_TOUT, /*Process time outed*/ + LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/ + LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/ + LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/ + LV_FS_RES_UNKNOWN, /*Other unknown error*/ +}; +typedef uint8_t lv_fs_res_t; + +struct __lv_fs_drv_t; + +typedef struct +{ + void * file_d; + struct __lv_fs_drv_t* drv; +} lv_fs_file_t; + + +typedef struct +{ + void * dir_d; + struct __lv_fs_drv_t * drv; +} lv_fs_dir_t; + +enum +{ + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + +typedef struct __lv_fs_drv_t +{ + char letter; + uint16_t file_size; + uint16_t rddir_size; + bool (*ready) (void); + + lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close) (void * file_p); + lv_fs_res_t (*remove) (const char * fn); + lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek) (void * file_p, uint32_t pos); + lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p); + lv_fs_res_t (*trunc) (void * file_p); + lv_fs_res_t (*size) (void * file_p, uint32_t * size_p); + lv_fs_res_t (*rename) (const char * oldname, const char * newname); + lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p); + + lv_fs_res_t (*dir_open) (void * rddir_p, const char * path); + lv_fs_res_t (*dir_read) (void * rddir_p, char * fn); + lv_fs_res_t (*dir_close) (void * rddir_p); +} lv_fs_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void); + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p); + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter); + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode); + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p); + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove (const char * path); + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p); + +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size); + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_rdir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p); + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p); + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf); + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn); + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path); + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FS_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_gc.c b/bdk/libs/lvgl/lv_misc/lv_gc.c new file mode 100644 index 0000000..5ec5832 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_gc.c @@ -0,0 +1,40 @@ +/** + * @file lv_gc.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_gc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +#if (!defined(LV_ENABLE_GC)) || LV_ENABLE_GC == 0 +LV_ROOTS +#endif /* LV_ENABLE_GC */ +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_misc/lv_gc.h b/bdk/libs/lvgl/lv_misc/lv_gc.h new file mode 100644 index 0000000..660d7f0 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_gc.h @@ -0,0 +1,75 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +#define LV_GC_ROOTS(prefix) \ + prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \ + prefix lv_ll_t _lv_scr_ll; /*Linked list of screens*/ \ + prefix lv_ll_t _lv_drv_ll;\ + prefix lv_ll_t _lv_file_ll;\ + prefix lv_ll_t _lv_anim_ll;\ + prefix void * _lv_def_scr;\ + prefix void * _lv_act_scr;\ + prefix void * _lv_top_layer;\ + prefix void * _lv_sys_layer;\ + prefix void * _lv_task_act;\ + prefix void * _lv_indev_list;\ + prefix void * _lv_disp_list;\ + +#define LV_NO_PREFIX +#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX) + +#if LV_ENABLE_GC == 1 +# if LV_MEM_CUSTOM != 1 +# error "GC requires CUSTOM_MEM" +# endif /* LV_MEM_CUSTOM */ +#else /* LV_ENABLE_GC */ +# define LV_GC_ROOT(x) x + LV_GC_ROOTS(extern) +#endif /* LV_ENABLE_GC */ + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GC_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_ll.c b/bdk/libs/lvgl/lv_misc/lv_ll.c new file mode 100644 index 0000000..43d8847 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_ll.c @@ -0,0 +1,376 @@ +/** + * @file lv_ll.c + * Handle linked lists. + * The nodes are dynamically allocated by the 'lv_mem' module, + */ + +/********************* + * INCLUDES + *********************/ +#include +#include + +#include "lv_ll.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LL_NODE_META_SIZE (sizeof(lv_ll_node_t*) + sizeof(lv_ll_node_t*)) +#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size) +#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t*)) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev); +static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size) +{ + ll_p->head = NULL; + ll_p->tail = NULL; +#ifdef LV_MEM_ENV64 + /*Round the size up to 8*/ + if(node_size & 0x7) { + node_size = node_size & (~0x7); + node_size += 8; + } +#else + /*Round the size up to 4*/ + if(node_size & 0x3) { + node_size = node_size & (~0x3); + node_size += 4; + } +#endif + + ll_p->n_size = node_size; +} + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p) +{ + lv_ll_node_t * n_new; + + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + + if(n_new != NULL) { + node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/ + node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/ + + if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/ + node_set_prev(ll_p, ll_p->head, n_new); + } + + ll_p->head = n_new; /*Set the new head in the dsc.*/ + if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/ + ll_p->tail = n_new; + } + } + + return n_new; +} + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act) +{ + lv_ll_node_t * n_new; + lv_ll_node_t * n_prev; + + if(NULL == ll_p || NULL == n_act) return NULL; + + if(lv_ll_get_head(ll_p) == n_act) { + n_new = lv_ll_ins_head(ll_p); + if(n_new == NULL) return NULL; + } else { + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + if(n_new == NULL) return NULL; + + n_prev = lv_ll_get_prev(ll_p, n_act); + node_set_next(ll_p, n_prev, n_new); + node_set_prev(ll_p, n_new, n_prev); + node_set_prev(ll_p, n_act, n_new); + node_set_next(ll_p, n_new, n_act); + } + + return n_new; +} + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p) +{ + lv_ll_node_t * n_new; + + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + if(n_new == NULL) return NULL; + + if(n_new != NULL) { + node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/ + node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/ + if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/ + node_set_next(ll_p, ll_p->tail, n_new); + } + + ll_p->tail = n_new; /*Set the new tail in the dsc.*/ + if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/ + ll_p->head = n_new; + } + } + + return n_new; +} + + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p) +{ + if(lv_ll_get_head(ll_p) == node_p) { + /*The new head will be the node after 'n_act'*/ + ll_p->head = lv_ll_get_next(ll_p, node_p); + if(ll_p->head == NULL) { + ll_p->tail = NULL; + } else { + node_set_prev(ll_p, ll_p->head, NULL); + } + } else if(lv_ll_get_tail(ll_p) == node_p) { + /*The new tail will be the node before 'n_act'*/ + ll_p->tail = lv_ll_get_prev(ll_p, node_p); + if(ll_p->tail == NULL) { + ll_p->head = NULL; + } else { + node_set_next(ll_p, ll_p->tail, NULL); + } + } else { + lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p); + lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p); + + node_set_next(ll_p, n_prev, n_next); + node_set_prev(ll_p, n_next, n_prev); + } +} + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p) +{ + void * i; + void * i_next; + + i = lv_ll_get_head(ll_p); + i_next = NULL; + + while(i != NULL) { + i_next = lv_ll_get_next(ll_p, i); + + lv_ll_rem(ll_p, i); + lv_mem_free(i); + + i = i_next; + } +} + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) +{ + lv_ll_rem(ll_ori_p, node); + + /*Set node as head*/ + node_set_prev(ll_new_p, node, NULL); + node_set_next(ll_new_p, node, ll_new_p->head); + + if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/ + node_set_prev(ll_new_p, ll_new_p->head, node); + } + + ll_new_p->head = node; /*Set the new head in the dsc.*/ + if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/ + ll_new_p->tail = node; + } +} + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p) +{ + void * head = NULL; + + if(ll_p != NULL) { + head = ll_p->head; + } + + return head; +} + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p) +{ + void * tail = NULL; + + if(ll_p != NULL) { + tail = ll_p->tail; + } + + return tail; +} + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act) +{ + void * next = NULL; + + if(ll_p != NULL) { + const lv_ll_node_t * n_act_d = n_act; + memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *)); + } + + return next; +} + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act) +{ + void * prev = NULL; + + if(ll_p != NULL) { + const lv_ll_node_t * n_act_d = n_act; + memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *)); + } + + return prev; +} + +void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p) +{ + (void)(ll_p); + (void)(n1_p); + (void)(n2_p); + /*TODO*/ +} + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) +{ + if(n_act == n_after) return; /*Can't move before itself*/ + + + void * n_before; + if(n_after != NULL) n_before = lv_ll_get_prev(ll_p, n_after); + else n_before = lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/ + + if(n_act == n_before) return; /*Already before `n_after`*/ + + /*It's much easier to remove from the list and add again*/ + lv_ll_rem(ll_p, n_act); + + /*Add again by setting the prev. and next nodes*/ + node_set_next(ll_p, n_before, n_act); + node_set_prev(ll_p, n_act, n_before); + node_set_prev(ll_p, n_after, n_act); + node_set_next(ll_p, n_act, n_after); + + /*If `n_act` was moved before NULL then it become the new tail*/ + if(n_after == NULL) ll_p->tail = n_act; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Set the 'pervious node pointer' of a node + * @param ll_p pointer to linked list + * @param act pointer to a node which prev. node pointer should be set + * @param prev pointer to a node which should be the previous node before 'act' + */ +static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev) +{ + if(act == NULL) return; /*Can't set the prev node of `NULL`*/ + + uint32_t node_p_size = sizeof(lv_ll_node_t *); + if(prev) memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size); + else memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size); +} + +/** + * Set the 'next node pointer' of a node + * @param ll_p pointer to linked list + * @param act pointer to a node which next node pointer should be set + * @param next pointer to a node which should be the next node before 'act' + */ +static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next) +{ + if(act == NULL) return; /*Can't set the next node of `NULL`*/ + + uint32_t node_p_size = sizeof(lv_ll_node_t *); + if(next) memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size); + else memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size); +} + diff --git a/bdk/libs/lvgl/lv_misc/lv_ll.h b/bdk/libs/lvgl/lv_misc/lv_ll.h new file mode 100644 index 0000000..086ba40 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_ll.h @@ -0,0 +1,145 @@ +/** + * @file lv_ll.c + * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. + */ + +#ifndef LV_LL_H +#define LV_LL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Dummy type to make handling easier*/ +typedef uint8_t lv_ll_node_t; + +/*Description of a linked list*/ +typedef struct +{ + uint32_t n_size; + lv_ll_node_t* head; + lv_ll_node_t* tail; +} lv_ll_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p); + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p); + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p); + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p); + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p); + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p); + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); + +/********************** + * MACROS + **********************/ + +#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) + +#define LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_log.c b/bdk/libs/lvgl/lv_misc/lv_log.c new file mode 100644 index 0000000..bd59cf3 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_log.c @@ -0,0 +1,82 @@ +/** + * @file lv_log.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_log.h" +#if USE_LV_LOG + +#if LV_LOG_PRINTF +#include +#include +#include +#include +#endif +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static void (*print_cb)(lv_log_level_t, const char *, uint32_t, const char *); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)) +{ + print_cb = f; +} + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc) +{ + if(level >= _LV_LOG_LEVEL_NUM) return; /*Invalid level*/ + + if(level >= LV_LOG_LEVEL) { + +#if LV_LOG_PRINTF + static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; + char *log = (char *)malloc(0x1000); + s_printf(log, "%s: %s \t(%s #%d)\r\n", lvl_prefix[level], dsc, file, line); + uart_send(UART_B, (u8 *)log, strlen(log) + 1); + //gfx_printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line); +#else + if(print_cb) print_cb(level, file, line, dsc); +#endif + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*USE_LV_LOG*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_log.h b/bdk/libs/lvgl/lv_misc/lv_log.h new file mode 100644 index 0000000..8e99763 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_log.h @@ -0,0 +1,86 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `USE_LV_LOG`*/ + +#define LV_LOG_LEVEL_TRACE 0 /*A lot of logs to give detailed information*/ +#define LV_LOG_LEVEL_INFO 1 /*Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /*Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_ERROR 3 /*Only critical issue, when the system may fail*/ +#define _LV_LOG_LEVEL_NUM 4 + +typedef int8_t lv_log_level_t; + +#if USE_LV_LOG +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)); + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); + +/********************** + * MACROS + **********************/ + +#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); + +#else /*USE_LV_LOG*/ + +/*Do nothing if `USE_LV_LOG 0`*/ +#define lv_log_add(level, file, line, dsc) {;} +#define LV_LOG_TRACE(dsc) {;} +#define LV_LOG_INFO(dsc) {;} +#define LV_LOG_WARN(dsc) {;} +#define LV_LOG_ERROR(dsc) {;} +#endif /*USE_LV_LOG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LOG_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_math.c b/bdk/libs/lvgl/lv_misc/lv_math.c new file mode 100644 index 0000000..a0d2605 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_math.c @@ -0,0 +1,165 @@ +/** + * @file lv_math.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_math.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static int16_t sin0_90_table[] = { + 0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126, + 5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668, + 11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886, + 16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, + 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730, + 25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087, + 28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591, + 30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165, + 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, + 32767 +}; + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf) +{ + char * buf_ori = buf; + if(num == 0) { + buf[0] = '0'; + buf[1] = '\0'; + return buf; + } else if(num < 0) { + (*buf) = '-'; + buf++; + num = LV_MATH_ABS(num); + } + uint32_t output = 0; + int8_t i; + + for(i = 31; i >= 0; i--) { + if((output & 0xF) >= 5) + output += 3; + if(((output & 0xF0) >> 4) >= 5) + output += (3 << 4); + if(((output & 0xF00) >> 8) >= 5) + output += (3 << 8); + if(((output & 0xF000) >> 12) >= 5) + output += (3 << 12); + if(((output & 0xF0000) >> 16) >= 5) + output += (3 << 16); + if(((output & 0xF00000) >> 20) >= 5) + output += (3 << 20); + if(((output & 0xF000000) >> 24) >= 5) + output += (3 << 24); + if(((output & 0xF0000000) >> 28) >= 5) + output += (3 << 28); + output = (output << 1) | ((num >> i) & 1); + } + + uint8_t digit; + bool leading_zero_ready = false; + for(i = 28; i >= 0; i -= 4) { + digit = ((output >> i) & 0xF) + '0'; + if(digit == '0' && leading_zero_ready == false) continue; + + leading_zero_ready = true; + (*buf) = digit; + buf++; + } + + (*buf) = '\0'; + + return buf_ori; +} + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle) +{ + int16_t ret = 0; + angle = angle % 360; + + if(angle < 0) angle = 360 + angle; + + if(angle < 90) { + ret = sin0_90_table[angle]; + } else if(angle >= 90 && angle < 180) { + angle = 180 - angle; + ret = sin0_90_table[angle]; + } else if(angle >= 180 && angle < 270) { + angle = angle - 180; + ret = - sin0_90_table[angle]; + } else { /*angle >=270*/ + angle = 360 - angle; + ret = - sin0_90_table[angle]; + } + + return ret; +} + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3) +{ + uint32_t t_rem = 1024 - t; + uint32_t t_rem2 = (t_rem * t_rem) >> 10; + uint32_t t_rem3 = (t_rem2 * t_rem) >> 10; + uint32_t t2 = (t * t) >> 10; + uint32_t t3 = (t2 * t) >> 10; + + + uint32_t v1 = ((uint32_t)t_rem3 * u0) >> 10; + uint32_t v2 = ((uint32_t)3 * t_rem2 * t * u1) >> 20; + uint32_t v3 = ((uint32_t)3 * t_rem * t2 * u2) >> 20; + uint32_t v4 = ((uint32_t)t3 * u3) >> 10; + + return v1 + v2 + v3 + v4; + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + diff --git a/bdk/libs/lvgl/lv_misc/lv_math.h b/bdk/libs/lvgl/lv_misc/lv_math.h new file mode 100644 index 0000000..a0229eb --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_math.h @@ -0,0 +1,73 @@ +/** + * @file math_base.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ +#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define LV_TRIGO_SIN_MAX 32767 +#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/ + +#define LV_BEZIER_VAL_MAX 1024 /*Max time in Bezier functions (not [0..1] to use integers) */ +#define LV_BEZIER_VAL_SHIFT 10 /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf); + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle); + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_mem.c b/bdk/libs/lvgl/lv_misc/lv_mem.c new file mode 100644 index 0000000..08f52d5 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_mem.c @@ -0,0 +1,470 @@ +/* + * 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 . + */ + +/** + * @file lv_mem.c + * General and portable implementation of malloc and free. + * The dynamic memory monitoring is also supported. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include "lv_math.h" +#include + +#include + +#if LV_MEM_CUSTOM != 0 +#include LV_MEM_CUSTOM_INCLUDE +#endif + +/********************* + * DEFINES + *********************/ +#define LV_MEM_ADD_JUNK 0 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/ + + +#ifdef LV_MEM_ENV64 +# define MEM_UNIT uint64_t +#else +# define MEM_UNIT uint32_t +#endif + + +/********************** + * TYPEDEFS + **********************/ + +#if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/ + +/*The size of this union must be 32 bytes (uint32_t * 8)*/ +typedef union { + struct { + MEM_UNIT used: 1; //1: if the entry is used + MEM_UNIT d_size: 31; //Size of the data + }; + MEM_UNIT header; //The header (used + d_size) + MEM_UNIT align[8]; //Align header size to MEM_UNIT * 8 bytes +} lv_mem_header_t; + +static_assert(sizeof(lv_mem_header_t) == 32, "Node header must be 32 bytes!"); + +typedef struct { + lv_mem_header_t header; + uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/ +} lv_mem_ent_t; + +#endif /* LV_ENABLE_GC */ + +/********************** + * STATIC PROTOTYPES + **********************/ +#if LV_MEM_CUSTOM == 0 +static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e); +static void * ent_alloc(lv_mem_ent_t * e, uint32_t size); +static void ent_trunc(lv_mem_ent_t * e, uint32_t size); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +#if LV_MEM_CUSTOM == 0 +static uint8_t * work_mem; +#endif + +static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initiaiize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void) +{ +#if LV_MEM_CUSTOM == 0 + +#if LV_MEM_ADR == 0 + /*Allocate a large array to store the dynamically allocated data*/ + static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)]; + work_mem = (uint8_t *) work_mem_int; +#else + work_mem = (uint8_t *) LV_MEM_ADR; +#endif + + lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem; + full->header.used = 0; + /*The total mem size id reduced by the first header and the close patterns */ + full->header.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t); +#endif +} + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size) +{ + if(size == 0) { + return &zero_mem; + } + + /*Round the size to lv_mem_header_t*/ + if(size & (sizeof(lv_mem_header_t) - 1)) { + size = size & (~(sizeof(lv_mem_header_t) - 1)); + size += sizeof(lv_mem_header_t); + } + + void * alloc = NULL; + +#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/ + lv_mem_ent_t * e = NULL; + + //Search for a appropriate entry + do { + //Get the next entry + e = ent_get_next(e); + + /*If there is next entry then try to allocate there*/ + if(e != NULL) { + alloc = ent_alloc(e, size); + } + //End if there is not next entry OR the alloc. is successful + } while(e != NULL && alloc == NULL); + + +#else /*Use custom, user defined malloc function*/ +#if LV_ENABLE_GC == 1 /*gc must not include header*/ + alloc = LV_MEM_CUSTOM_ALLOC(size); +#else /* LV_ENABLE_GC */ + /*Allocate a header too to store the size*/ + alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t)); + if(alloc != NULL) { + ((lv_mem_ent_t *) alloc)->header.d_size = size; + ((lv_mem_ent_t *) alloc)->header.used = 1; + alloc = &((lv_mem_ent_t *) alloc)->first_data; + } +#endif /* LV_ENABLE_GC */ +#endif /* LV_MEM_CUSTOM */ + +#if LV_MEM_ADD_JUNK + if(alloc != NULL) memset(alloc, 0xaa, size); +#endif + + if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory"); + + return alloc; +} + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data) +{ + if(data == &zero_mem) return; + if(data == NULL) return; + + +#if LV_MEM_ADD_JUNK + memset((void *)data, 0xbb, lv_mem_get_size(data)); +#endif + +#if LV_ENABLE_GC==0 + /*e points to the header*/ + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t)); + e->header.used = 0; +#endif + +#if LV_MEM_CUSTOM == 0 +#if LV_MEM_AUTO_DEFRAG + /* Make a simple defrag. + * Join the following free entries after this*/ + lv_mem_ent_t * e_next; + e_next = ent_get_next(e); + while(e_next != NULL) { + if(e_next->header.used == 0) { + e->header.d_size += e_next->header.d_size + sizeof(e->header); + } else { + break; + } + e_next = ent_get_next(e_next); + } +#endif +#else /*Use custom, user defined free function*/ +#if LV_ENABLE_GC==0 + LV_MEM_CUSTOM_FREE(e); +#else + LV_MEM_CUSTOM_FREE((void*)data); +#endif /*LV_ENABLE_GC*/ +#endif +} + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ + +#if LV_ENABLE_GC==0 + +void * lv_mem_realloc(void * data_p, uint32_t new_size) +{ + /*Round the size to lv_mem_header_t*/ + if(new_size & (sizeof(lv_mem_header_t) - 1)) { + new_size = new_size & (~(sizeof(lv_mem_header_t) - 1)); + new_size += sizeof(lv_mem_header_t); + } + + /*data_p could be previously freed pointer (in this case it is invalid)*/ + if(data_p != NULL) { + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t)); + if(e->header.used == 0) { + data_p = NULL; + } + } + + uint32_t old_size = lv_mem_get_size(data_p); + if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/ + +#if LV_MEM_CUSTOM == 0 + /* Only truncate the memory is possible + * If the 'old_size' was extended by a header size in 'ent_trunc' it avoids reallocating this same memory */ + if(new_size < old_size) { + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t)); + ent_trunc(e, new_size); + return &e->first_data; + } +#endif + + void * new_p; + new_p = lv_mem_alloc(new_size); + + if(new_p != NULL && data_p != NULL) { + /*Copy the old data to the new. Use the smaller size*/ + if(old_size != 0) { + memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size)); + lv_mem_free(data_p); + } + } + + + if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory"); + + return new_p; +} + +#else /* LV_ENABLE_GC */ + +void * lv_mem_realloc(void * data_p, uint32_t new_size) +{ + void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size); + if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory"); + return new_p; +} + +#endif /* lv_enable_gc */ + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void) +{ +#if LV_MEM_CUSTOM == 0 + lv_mem_ent_t * e_free; + lv_mem_ent_t * e_next; + e_free = ent_get_next(NULL); + + while(1) { + /*Search the next free entry*/ + while(e_free != NULL) { + if(e_free->header.used != 0) { + e_free = ent_get_next(e_free); + } else { + break; + } + } + + if(e_free == NULL) return; + + /*Joint the following free entries to the free*/ + e_next = ent_get_next(e_free); + while(e_next != NULL) { + if(e_next->header.used == 0) { + e_free->header.d_size += e_next->header.d_size + sizeof(e_next->header); + } else { + break; + } + + e_next = ent_get_next(e_next); + } + + if(e_next == NULL) return; + + /*Continue from the lastly checked entry*/ + e_free = e_next; + } +#endif +} + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p) +{ + /*Init the data*/ + memset(mon_p, 0, sizeof(lv_mem_monitor_t)); +#if LV_MEM_CUSTOM == 0 + lv_mem_ent_t * e; + e = NULL; + + e = ent_get_next(e); + + while(e != NULL) { + if(e->header.used == 0) { + mon_p->free_cnt++; + mon_p->free_size += e->header.d_size; + if(e->header.d_size > mon_p->free_biggest_size) { + mon_p->free_biggest_size = e->header.d_size; + } + } else { + mon_p->used_cnt++; + } + + e = ent_get_next(e); + } + mon_p->total_size = LV_MEM_SIZE; + mon_p->used_pct = 100 - ((uint64_t)100U * mon_p->free_size) / mon_p->total_size; + mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size; + mon_p->frag_pct = 100 - mon_p->frag_pct; +#endif +} + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ + +#if LV_ENABLE_GC==0 + +uint32_t lv_mem_get_size(const void * data) +{ + if(data == NULL) return 0; + if(data == &zero_mem) return 0; + + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t)); + + return e->header.d_size; +} + +#else /* LV_ENABLE_GC */ + +uint32_t lv_mem_get_size(const void * data) +{ + return LV_MEM_CUSTOM_GET_SIZE(data); +} + +#endif /*LV_ENABLE_GC*/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_MEM_CUSTOM == 0 +/** + * Give the next entry after 'act_e' + * @param act_e pointer to an entry + * @return pointer to an entry after 'act_e' + */ +static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e) +{ + lv_mem_ent_t * next_e = NULL; + + if(act_e == NULL) { /*NULL means: get the first entry*/ + next_e = (lv_mem_ent_t *) work_mem; + } else { /*Get the next entry */ + uint8_t * data = &act_e->first_data; + next_e = (lv_mem_ent_t *)&data[act_e->header.d_size]; + + if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL; + } + + return next_e; +} + + +/** + * Try to do the real allocation with a given size + * @param e try to allocate to this entry + * @param size size of the new memory in bytes + * @return pointer to the allocated memory or NULL if not enough memory in the entry + */ +static void * ent_alloc(lv_mem_ent_t * e, uint32_t size) +{ + void * alloc = NULL; + + /*If the memory is free and big enough then use it */ + if(e->header.used == 0 && e->header.d_size >= size) { + /*Truncate the entry to the desired size */ + ent_trunc(e, size), + + e->header.used = 1; + + /*Save the allocated data*/ + alloc = &e->first_data; + } + + return alloc; +} + +/** + * Truncate the data of entry to the given size + * @param e Pointer to an entry + * @param size new size in bytes + */ +static void ent_trunc(lv_mem_ent_t * e, uint32_t size) +{ + /*Don't let empty space only for a header without data*/ + if(e->header.d_size == size + sizeof(lv_mem_header_t)) { + size = e->header.d_size; + } + + /* Create the new entry after the current if there is space for it */ + if(e->header.d_size != size) { + uint8_t * e_data = &e->first_data; + lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size]; + after_new_e->header.used = 0; + after_new_e->header.d_size = e->header.d_size - size - sizeof(lv_mem_header_t); + } + + /* Set the new size for the original entry */ + e->header.d_size = size; +} + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_mem.h b/bdk/libs/lvgl/lv_misc/lv_mem.h new file mode 100644 index 0000000..c33caa4 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_mem.h @@ -0,0 +1,127 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ +// Check windows +#ifdef __WIN64 +//# define LV_MEM_ENV64 +#endif + +// Check GCC +#ifdef __GNUC__ +# if defined(__x86_64__) || defined(__ppc64__) +//# define LV_MEM_ENV64 +# endif +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t total_size; + uint32_t free_cnt; + uint32_t free_size; + uint32_t free_biggest_size; + uint32_t used_cnt; + uint8_t used_pct; + uint8_t frag_pct; +} lv_mem_monitor_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initiaize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void); + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data); + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ +void * lv_mem_realloc(void * data_p, uint32_t new_size); + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ +uint32_t lv_mem_get_size(const void * data); + + +/********************** + * MACROS + **********************/ + +/** + * Halt on NULL pointer + * p pointer to a memory + */ +#if USE_LV_LOG == 0 +# define lv_mem_assert(p) {if(p == NULL) while(1); } +#else +# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }} +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MEM_H*/ + diff --git a/bdk/libs/lvgl/lv_misc/lv_misc.mk b/bdk/libs/lvgl/lv_misc/lv_misc.mk new file mode 100644 index 0000000..470f123 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_misc.mk @@ -0,0 +1,19 @@ +CSRCS += lv_font.c +CSRCS += lv_circ.c +CSRCS += lv_area.c +CSRCS += lv_task.c +CSRCS += lv_fs.c +CSRCS += lv_anim.c +CSRCS += lv_mem.c +CSRCS += lv_ll.c +CSRCS += lv_color.c +CSRCS += lv_txt.c +CSRCS += lv_ufs.c +CSRCS += lv_math.c +CSRCS += lv_log.c +CSRCS += lv_gc.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc +VPATH += :$(LVGL_DIR)/lvgl/lv_misc + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc" diff --git a/bdk/libs/lvgl/lv_misc/lv_symbol_def.h b/bdk/libs/lvgl/lv_misc/lv_symbol_def.h new file mode 100644 index 0000000..762bab9 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_symbol_def.h @@ -0,0 +1,223 @@ +/* + * 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 . + */ + +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +/* + * With no UTF-8 support (192- 255) (192..241 is used) + * + * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831 + * - Basic symbols: 0xE000..0xE01F + * - File symbols: 0xE020..0xE03F + * - Feedback symbols: 0xE040..0xE05F + * - Reserved: 0xE060..0xE07F + */ + +#if LV_TXT_UTF8 == 0 +#define LV_SYMBOL_GLYPH_FIRST 0xC0 +#define SYMBOL_DOT _SYMBOL_VALUE1(C0) +#define SYMBOL_CLOCK _SYMBOL_VALUE1(C1) +#define SYMBOL_LIST _SYMBOL_VALUE1(C2) +#define SYMBOL_OK _SYMBOL_VALUE1(C3) +#define SYMBOL_CLOSE _SYMBOL_VALUE1(C4) +#define SYMBOL_POWER _SYMBOL_VALUE1(C5) +#define SYMBOL_SETTINGS _SYMBOL_VALUE1(C6) +#define SYMBOL_TRASH _SYMBOL_VALUE1(C7) +#define SYMBOL_HOME _SYMBOL_VALUE1(C8) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE1(C9) +#define SYMBOL_DRIVE _SYMBOL_VALUE1(CA) +#define SYMBOL_REFRESH _SYMBOL_VALUE1(CB) +#define SYMBOL_REBOOT _SYMBOL_VALUE1(CC) +#define SYMBOL_CHIP _SYMBOL_VALUE1(CD) +#define SYMBOL_SD _SYMBOL_VALUE1(CE) +#define SYMBOL_CIRCUIT _SYMBOL_VALUE1(CF) +#define SYMBOL_EDIT _SYMBOL_VALUE1(D0) +#define SYMBOL_FILE_ALT _SYMBOL_VALUE1(D1) +#define SYMBOL_FILE_CODE _SYMBOL_VALUE1(D2) +#define SYMBOL_FILE_ARC _SYMBOL_VALUE1(D3) +#define SYMBOL_TEMPERATURE _SYMBOL_VALUE1(D4) +#define SYMBOL_MODULES _SYMBOL_VALUE1(D5) +#define SYMBOL_MODULES_ALT _SYMBOL_VALUE1(D6) +#define SYMBOL_LEFT _SYMBOL_VALUE1(D7) +#define SYMBOL_RIGHT _SYMBOL_VALUE1(D8) +#define SYMBOL_KEY _SYMBOL_VALUE1(D9) +#define SYMBOL_INFO _SYMBOL_VALUE1(DA) +#define SYMBOL_WARNING _SYMBOL_VALUE1(DB) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE1(DC) +#define SYMBOL_UP _SYMBOL_VALUE1(DD) +#define SYMBOL_DOWN _SYMBOL_VALUE1(DE) +#define SYMBOL_BRIGHTNESS _SYMBOL_VALUE1(DF) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE1(E0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE1(E1) +#define SYMBOL_USB _SYMBOL_VALUE1(E2) +#define SYMBOL_TOOLS _SYMBOL_VALUE1(E3) +#define SYMBOL_COPY _SYMBOL_VALUE1(E4) +#define SYMBOL_SAVE _SYMBOL_VALUE1(E5) +#define SYMBOL_CHARGE _SYMBOL_VALUE1(E6) +#define SYMBOL_HINT _SYMBOL_VALUE1(E7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE1(E8) +#define SYMBOL_GPS _SYMBOL_VALUE1(E9) +#define SYMBOL_FILE _SYMBOL_VALUE1(EA) +#define SYMBOL_CAMERA _SYMBOL_VALUE1(EB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE1(EC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE1(ED) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE1(EE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE1(EF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE1(F0) +#define SYMBOL_SHRK _SYMBOL_VALUE1(F1) +#define LV_SYMBOL_GLYPH_LAST 0xF1 +#define SYMBOL_DUMMY _SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/ + +#else +#define LV_SYMBOL_GLYPH_FIRST 0xF800 +#define SYMBOL_DOT _SYMBOL_VALUE3(EF,A0,80) +#define SYMBOL_CLOCK _SYMBOL_VALUE3(EF,A0,81) +#define SYMBOL_LIST _SYMBOL_VALUE3(EF,A0,82) +#define SYMBOL_OK _SYMBOL_VALUE3(EF,A0,83) +#define SYMBOL_CLOSE _SYMBOL_VALUE3(EF,A0,84) +#define SYMBOL_POWER _SYMBOL_VALUE3(EF,A0,85) +#define SYMBOL_SETTINGS _SYMBOL_VALUE3(EF,A0,86) +#define SYMBOL_TRASH _SYMBOL_VALUE3(EF,A0,87) +#define SYMBOL_HOME _SYMBOL_VALUE3(EF,A0,88) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE3(EF,A0,89) +#define SYMBOL_DRIVE _SYMBOL_VALUE3(EF,A0,8A) +#define SYMBOL_REFRESH _SYMBOL_VALUE3(EF,A0,8B) +#define SYMBOL_REBOOT _SYMBOL_VALUE3(EF,A0,8C) +#define SYMBOL_CHIP _SYMBOL_VALUE3(EF,A0,8D) +#define SYMBOL_SD _SYMBOL_VALUE3(EF,A0,8E) +#define SYMBOL_CIRCUIT _SYMBOL_VALUE3(EF,A0,8F) +#define SYMBOL_EDIT _SYMBOL_VALUE3(EF,A0,90) +#define SYMBOL_FILE_ALT _SYMBOL_VALUE3(EF,A0,91) +#define SYMBOL_FILE_CODE _SYMBOL_VALUE3(EF,A0,92) +#define SYMBOL_FILE_ARC _SYMBOL_VALUE3(EF,A0,93) +#define SYMBOL_TEMPERATURE _SYMBOL_VALUE3(EF,A0,94) +#define SYMBOL_MODULES _SYMBOL_VALUE3(EF,A0,95) +#define SYMBOL_MODULES_ALT _SYMBOL_VALUE3(EF,A0,96) +#define SYMBOL_LEFT _SYMBOL_VALUE3(EF,A0,97) +#define SYMBOL_RIGHT _SYMBOL_VALUE3(EF,A0,98) +#define SYMBOL_KEY _SYMBOL_VALUE3(EF,A0,99) +#define SYMBOL_INFO _SYMBOL_VALUE3(EF,A0,9A) +#define SYMBOL_WARNING _SYMBOL_VALUE3(EF,A0,9B) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE3(EF,A0,9C) +#define SYMBOL_UP _SYMBOL_VALUE3(EF,A0,9D) +#define SYMBOL_DOWN _SYMBOL_VALUE3(EF,A0,9E) +#define SYMBOL_BRIGHTNESS _SYMBOL_VALUE3(EF,A0,9F) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE3(EF,A0,A0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE3(EF,A0,A1) +#define SYMBOL_USB _SYMBOL_VALUE3(EF,A0,A2) +#define SYMBOL_TOOLS _SYMBOL_VALUE3(EF,A0,A3) +#define SYMBOL_COPY _SYMBOL_VALUE3(EF,A0,A4) +#define SYMBOL_SAVE _SYMBOL_VALUE3(EF,A0,A5) +#define SYMBOL_CHARGE _SYMBOL_VALUE3(EF,A0,A6) +#define SYMBOL_HINT _SYMBOL_VALUE3(EF,A0,A7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE3(EF,A0,A8) +#define SYMBOL_GPS _SYMBOL_VALUE3(EF,A0,A9) +#define SYMBOL_FILE _SYMBOL_VALUE3(EF,A0,AA) +#define SYMBOL_CAMERA _SYMBOL_VALUE3(EF,A0,AB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE3(EF,A0,AC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE3(EF,A0,AD) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE3(EF,A0,AE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE3(EF,A0,AF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE3(EF,A0,B0) +#define SYMBOL_SHRK _SYMBOL_VALUE3(EF,A0,B1) +#define LV_SYMBOL_GLYPH_LAST 0xF831 +#define SYMBOL_DUMMY _SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/ +#endif + +#define _SYMBOL_VALUE1(x) (0x ## x) +#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x) +#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym + +enum +{ + _SYMBOL_NUMSTR(SYMBOL_DOT), + _SYMBOL_NUMSTR(SYMBOL_CLOCK), + _SYMBOL_NUMSTR(SYMBOL_LIST), + _SYMBOL_NUMSTR(SYMBOL_OK), + _SYMBOL_NUMSTR(SYMBOL_CLOSE), + _SYMBOL_NUMSTR(SYMBOL_POWER), + _SYMBOL_NUMSTR(SYMBOL_SETTINGS), + _SYMBOL_NUMSTR(SYMBOL_TRASH), + _SYMBOL_NUMSTR(SYMBOL_HOME), + _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD), + _SYMBOL_NUMSTR(SYMBOL_DRIVE), + _SYMBOL_NUMSTR(SYMBOL_REFRESH), + _SYMBOL_NUMSTR(SYMBOL_REBOOT), + _SYMBOL_NUMSTR(SYMBOL_CHIP), + _SYMBOL_NUMSTR(SYMBOL_SD), + _SYMBOL_NUMSTR(SYMBOL_CIRCUIT), + _SYMBOL_NUMSTR(SYMBOL_EDIT), + _SYMBOL_NUMSTR(SYMBOL_FILE_ALT), + _SYMBOL_NUMSTR(SYMBOL_FILE_CODE), + _SYMBOL_NUMSTR(SYMBOL_FILE_ARC), + _SYMBOL_NUMSTR(SYMBOL_TEMPERATURE), + _SYMBOL_NUMSTR(SYMBOL_MODULES), + _SYMBOL_NUMSTR(SYMBOL_MODULES_ALT), + _SYMBOL_NUMSTR(SYMBOL_LEFT), + _SYMBOL_NUMSTR(SYMBOL_RIGHT), + _SYMBOL_NUMSTR(SYMBOL_KEY), + _SYMBOL_NUMSTR(SYMBOL_INFO), + _SYMBOL_NUMSTR(SYMBOL_WARNING), + _SYMBOL_NUMSTR(SYMBOL_SHUFFLE), + _SYMBOL_NUMSTR(SYMBOL_UP), + _SYMBOL_NUMSTR(SYMBOL_DOWN), + _SYMBOL_NUMSTR(SYMBOL_BRIGHTNESS), + _SYMBOL_NUMSTR(SYMBOL_DIRECTORY), + _SYMBOL_NUMSTR(SYMBOL_UPLOAD), + _SYMBOL_NUMSTR(SYMBOL_USB), + _SYMBOL_NUMSTR(SYMBOL_TOOLS), + _SYMBOL_NUMSTR(SYMBOL_COPY), + _SYMBOL_NUMSTR(SYMBOL_SAVE), + _SYMBOL_NUMSTR(SYMBOL_CHARGE), + _SYMBOL_NUMSTR(SYMBOL_HINT), + _SYMBOL_NUMSTR(SYMBOL_KEYBOARD), + _SYMBOL_NUMSTR(SYMBOL_GPS), + _SYMBOL_NUMSTR(SYMBOL_FILE), + _SYMBOL_NUMSTR(SYMBOL_CAMERA), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_3), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_2), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_1), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY), + _SYMBOL_NUMSTR(SYMBOL_SHRK), + _SYMBOL_NUMSTR(SYMBOL_DUMMY), +}; + +#undef _SYMBOL_VALUE1 +#undef _SYMBOL_VALUE3 + +#define _SYMBOL_STR_(x) #x +#define _SYMBOL_STR(x) _SYMBOL_STR_(x) +#define _SYMBOL_CHAR(c) \x ## c +#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x)) +#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_task.c b/bdk/libs/lvgl/lv_misc/lv_task.c new file mode 100644 index 0000000..aac9c12 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_task.c @@ -0,0 +1,332 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_task.h" +#include "../lv_hal/lv_hal_tick.h" +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ +#define IDLE_MEAS_PERIOD 500 /*[ms]*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_task_exec(lv_task_t * lv_task_p); + +/********************** + * STATIC VARIABLES + **********************/ +static bool lv_task_run = false; +static uint8_t idle_last = 0; +static bool task_deleted; +static bool task_created; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t)); + + /*Initially enable the lv_task handling*/ + lv_task_enable(true); +} + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) +{ + LV_LOG_TRACE("lv_task_handler started"); + + /*Avoid concurrent running of the task handler*/ + static bool task_handler_mutex = false; + if(task_handler_mutex) return; + task_handler_mutex = true; + + static uint32_t idle_period_start = 0; + static uint32_t handler_start = 0; + static uint32_t busy_time = 0; + + if(lv_task_run == false) return; + + handler_start = lv_tick_get(); + + /* Run all task from the highest to the lowest priority + * If a lower priority task is executed check task again from the highest priority + * but on the priority of executed tasks don't run tasks before the executed*/ + lv_task_t * task_interrupter = NULL; + lv_task_t * next; + bool end_flag; + do { + end_flag = true; + task_deleted = false; + task_created = false; + LV_GC_ROOT(_lv_task_act) = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + while(LV_GC_ROOT(_lv_task_act)) { + /* The task might be deleted if it runs only once ('once = 1') + * So get next element until the current is surely valid*/ + next = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act)); + + /*We reach priority of the turned off task. There is nothing more to do.*/ + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) { + break; + } + + /*Here is the interrupter task. Don't execute it again.*/ + if(LV_GC_ROOT(_lv_task_act) == task_interrupter) { + task_interrupter = NULL; /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/ + LV_GC_ROOT(_lv_task_act) = next; + continue; /*Load the next task*/ + } + + /*Just try to run the tasks with highest priority.*/ + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) { + lv_task_exec(LV_GC_ROOT(_lv_task_act)); + } + /*Tasks with higher priority then the interrupted shall be run in every case*/ + else if(task_interrupter) { + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) { + if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) { + task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */ + end_flag = false; + break; + } + } + } + /* It is no interrupter task or we already reached it earlier. + * Just run the remaining tasks*/ + else { + if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) { + task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */ + end_flag = false; + break; + } + } + + if(task_deleted) break; /*If a task was deleted then this or the next item might be corrupted*/ + if(task_created) break; /*If a task was deleted then this or the next item might be corrupted*/ + + LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/ + } + } while(!end_flag); + + busy_time += lv_tick_elaps(handler_start); + uint32_t idle_period_time = lv_tick_elaps(idle_period_start); + if(idle_period_time >= IDLE_MEAS_PERIOD) { + + idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/ + idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/ + busy_time = 0; + idle_period_start = lv_tick_get(); + + + } + + task_handler_mutex = false; /*Release the mutex*/ + + LV_LOG_TRACE("lv_task_handler ready"); +} + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param) +{ + lv_task_t * new_lv_task = NULL; + lv_task_t * tmp; + + /*Create task lists in order of priority from high to low*/ + tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + if(NULL == tmp) { /*First task*/ + new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + } else { + do { + if(tmp->prio <= prio) { + new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + break; + } + tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp); + } while(tmp != NULL); + + if(tmp == NULL) { /*Only too high priority tasks were found*/ + new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + } + } + + new_lv_task->period = period; + new_lv_task->task = task; + new_lv_task->prio = prio; + new_lv_task->param = param; + new_lv_task->once = 0; + new_lv_task->last_run = lv_tick_get(); + + task_created = true; + + return new_lv_task; +} + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t * lv_task_p) +{ + lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p); + + lv_mem_free(lv_task_p); + + if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/ +} + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio) +{ + /*Find the tasks with new priority*/ + lv_task_t * i; + LL_READ(LV_GC_ROOT(_lv_task_ll), i) { + if(i->prio <= prio) { + if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i); + break; + } + } + + /*There was no such a low priority so far then add the node to the tail*/ + if(i == NULL) { + lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL); + } + + + lv_task_p->prio = prio; +} + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period) +{ + lv_task_p->period = period; +} + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t * lv_task_p) +{ + lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1; +} + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p) +{ + lv_task_p->once = 1; +} + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t * lv_task_p) +{ + lv_task_p->last_run = lv_tick_get(); +} + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en) +{ + lv_task_run = en; +} + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void) +{ + return idle_last; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Execute task if its the priority is appropriate + * @param lv_task_p pointer to lv_task + * @return true: execute, false: not executed + */ +static bool lv_task_exec(lv_task_t * lv_task_p) +{ + bool exec = false; + + /*Execute if at least 'period' time elapsed*/ + uint32_t elp = lv_tick_elaps(lv_task_p->last_run); + if(elp >= lv_task_p->period) { + lv_task_p->last_run = lv_tick_get(); + task_deleted = false; + task_created = false; + lv_task_p->task(lv_task_p->param); + + /*Delete if it was a one shot lv_task*/ + if(task_deleted == false) { /*The task might be deleted by itself as well*/ + if(lv_task_p->once != 0) { + lv_task_del(lv_task_p); + } + } + exec = true; + } + + return exec; +} + diff --git a/bdk/libs/lvgl/lv_misc/lv_task.h b/bdk/libs/lvgl/lv_misc/lv_task.h new file mode 100644 index 0000000..aa6c903 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_task.h @@ -0,0 +1,149 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +#ifndef LV_TASK_H +#define LV_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER +#endif +/********************** + * TYPEDEFS + **********************/ +/** + * Possible priorities for lv_tasks + */ +#define LV_TASK_ONESHOT 0 +enum +{ + LV_TASK_PRIO_OFF = 0, + LV_TASK_PRIO_LOWEST, + LV_TASK_PRIO_LOW, + LV_TASK_PRIO_MID, + LV_TASK_PRIO_HIGH, + LV_TASK_PRIO_HIGHEST, + LV_TASK_PRIO_NUM, +}; +typedef uint8_t lv_task_prio_t; + +/** + * Descriptor of a lv_task + */ +typedef struct +{ + uint32_t period; + uint32_t last_run; + void (*task) (void*); + void * param; + uint8_t prio:3; + uint8_t once:1; +} lv_task_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void); + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param); + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t* lv_task_p); + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio); + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period); + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t* lv_task_p); + + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p); + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t* lv_task_p); + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en); + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_misc/lv_templ.c b/bdk/libs/lvgl/lv_misc/lv_templ.c new file mode 100644 index 0000000..11478b7 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_templ.c @@ -0,0 +1,36 @@ +/** + * @file lv_templ.c + * + */ + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_misc/lv_templ.h b/bdk/libs/lvgl/lv_misc/lv_templ.h new file mode 100644 index 0000000..a5459e8 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_templ.h @@ -0,0 +1,38 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_txt.c b/bdk/libs/lvgl/lv_misc/lv_txt.c new file mode 100644 index 0000000..d80c3b4 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_txt.c @@ -0,0 +1,793 @@ +/** + * @file lv_text.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_txt.h" +#include "lv_math.h" + +/********************* + * DEFINES + *********************/ +#define NO_BREAK_FOUND UINT32_MAX + +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#endif + +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#endif + +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool is_break_char(uint32_t letter); + +#if LV_TXT_UTF8 +static uint8_t lv_txt_utf8_size(const char * str); +static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni); +static uint32_t lv_txt_utf8_conv_wc(uint32_t c); +static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i); +static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start); +static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id); +static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id); +static uint32_t lv_txt_utf8_get_length(const char * txt); +#else +static uint8_t lv_txt_ascii_size(const char * str); +static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni); +static uint32_t lv_txt_ascii_conv_wc(uint32_t c); +static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i); +static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i_start); +static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id); +static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id); +static uint32_t lv_txt_ascii_get_length(const char * txt); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + + +/********************** + * GLOBAL VARIABLES + **********************/ +#if LV_TXT_UTF8 +uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size; +uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc; +uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next; +uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev; +uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id; +uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; +uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length; +#else +uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_ascii_size; +uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_ascii; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_ascii_conv_wc; +uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_ascii_next; +uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_ascii_prev; +uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_ascii_get_byte_id; +uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_ascii_get_char_id; +uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_ascii_get_length; +#endif +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param txt.line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag) +{ + size_res->x = 0; + size_res->y = 0; + + if(text == NULL) return; + if(font == NULL) return; + + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; + + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t act_line_length; + uint8_t letter_height = lv_font_get_height(font); + + /*Calc. the height and longest line*/ + while(text[line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag); + size_res->y += letter_height ; + size_res->y += line_space; + + /*Calculate the the longest line*/ + act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start, + font, letter_space, flag); + + size_res->x = LV_MATH_MAX(act_line_length, size_res->x); + line_start = new_line_start; + } + + /*Make the text one line taller if the last character is '\n' or '\r'*/ + if((line_start != 0) && (text[line_start - 1] == '\n' || text[line_start - 1] == '\r')) { + size_res->y += letter_height + line_space; + } + + /*Correction with the last line space or set the height manually if the text is empty*/ + if(size_res->y == 0) size_res->y = letter_height; + else size_res->y -= line_space; + +} + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag) +{ + if(txt == NULL) return 0; + if(font == NULL) return 0; + + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; + + uint32_t i = 0; + lv_coord_t cur_w = 0; + lv_coord_t w_at_last_break = 0; + uint32_t n_char_since_last_break = 0; /* Used count word length of long words */ + uint32_t last_break = NO_BREAK_FOUND; + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t letter = 0; + + while(txt[i] != '\0') { + lv_coord_t letter_width; + letter = lv_txt_encoded_next(txt, &i); + + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + + /*Check for new line chars*/ + if(letter == '\n' || letter == '\r') { + uint32_t i_tmp = i; + uint32_t letter_next = lv_txt_encoded_next(txt, &i_tmp); + if(letter == '\r' && letter_next == '\n') i = i_tmp; + + return i; /*Return with the first letter of the next line*/ + + } else { /*Check the actual length*/ + n_char_since_last_break++; + letter_width = lv_font_get_width(font, letter); + cur_w += letter_width; + + /* Get the length of the current work and determine best place + * to break the line. */ + if(cur_w > max_width) { + if( last_break != NO_BREAK_FOUND ) { + /* Continue searching for next breakable character to see if the next word will fit */ + uint32_t n_char_fit = n_char_since_last_break - 1; + if( n_char_since_last_break <= LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN ) { + i = last_break; + } + else { + uint32_t i_tmp = i; + cur_w -= w_at_last_break + letter_space; /*ignore the first letter_space after the break char */ + bool other = true; + while(txt[i_tmp] != '\0') { + letter = lv_txt_encoded_next(txt, &i_tmp); + + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + /*Check for new line chars*/ + if(letter == '\n' || letter == '\r' || is_break_char(letter)) { + if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) { + /* Figure out the prettiest place to break */ + uint32_t char_remain; + lv_txt_encoded_prev(txt, &i); + for(char_remain=n_char_since_last_break - n_char_fit; + char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN; + char_remain++) { + lv_txt_encoded_prev(txt, &i); + } + } + else{ + i = last_break; + } + other = false; + break; + } + n_char_since_last_break++; + lv_coord_t letter_width2 = lv_font_get_width(font, letter); + cur_w += letter_width2; + if(cur_w > max_width) { + /* Current letter already exceeds, return previous */ + lv_txt_encoded_prev(txt, &i); + other = false; + break; + } + if(letter_width2 > 0){ + cur_w += letter_space; + } + } + if( other ) { + if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) { + /* Figure out the prettiest place to break */ + uint32_t char_remain; + lv_txt_encoded_prev(txt, &i); + for(char_remain=n_char_since_last_break - n_char_fit; + char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN; + char_remain++){ + lv_txt_encoded_prev(txt, &i); + } + } + else{ + i = last_break; + } + } + } + } else { + /* Now this character is out of the area so it will be first character of the next line*/ + /* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/ + lv_txt_encoded_prev(txt, &i); + } + + /* Do not let to return without doing nothing. + * Find at least one character (Avoid infinite loop )*/ + if(i == 0) lv_txt_encoded_next(txt, &i); + + return i; + } + /*If this char still can fit to this line then check if + * txt can be broken here later */ + else if(is_break_char(letter)) { + last_break = i; /*Save the first char index after break*/ + w_at_last_break = cur_w; + if(letter_width > 0) { + w_at_last_break += letter_space; + } + n_char_since_last_break = 0; + } + } + + if(letter_width > 0) { + cur_w += letter_space; + } + } + + return i; +} + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag) +{ + if(txt == NULL) return 0; + if(font == NULL) return 0; + + uint32_t i = 0; + lv_coord_t width = 0; + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t letter; + + if(length != 0) { + while(i< length){ + letter = lv_txt_encoded_next(txt, &i); + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; + } + } + + lv_coord_t char_width = lv_font_get_width(font, letter); + if(char_width > 0){ + width += char_width; + width += letter_space; + } + } + + if(width > 0) { + width -= letter_space; /*Trim the last letter space. Important if the text is center aligned */ + } + } + + return width; +} + +/** + * Check next character in a string and decide if the character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * (Initied. to TXT_CMD_STATE_WAIT ) + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c) +{ + bool ret = false; + + if(c == (uint32_t)LV_TXT_COLOR_CMD[0]) { + if(*state == LV_TXT_CMD_STATE_WAIT) { /*Start char*/ + *state = LV_TXT_CMD_STATE_PAR; + ret = true; + } else if(*state == LV_TXT_CMD_STATE_PAR) { /*Other start char in parameter is escaped cmd. char */ + *state = LV_TXT_CMD_STATE_WAIT; + } else if(*state == LV_TXT_CMD_STATE_IN) { /*Command end */ + *state = LV_TXT_CMD_STATE_WAIT; + ret = true; + } + } + + /*Skip the color parameter and wait the space after it*/ + if(*state == LV_TXT_CMD_STATE_PAR) { + if(c == ' ') { + *state = LV_TXT_CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + ret = true; + } + + return ret; +} + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before the original text, 1: after the first char etc. + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) +{ + uint32_t old_len = strlen(txt_buf); + uint32_t ins_len = strlen(ins_txt); + uint32_t new_len = ins_len + old_len; +#if LV_TXT_UTF8 != 0 + pos = lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/ +#endif + /*Copy the second part into the end to make place to text to insert*/ + uint32_t i; + for(i = new_len; i >= pos + ins_len; i--) { + txt_buf[i] = txt_buf[i - ins_len]; + } + + /* Copy the text into the new space*/ + memcpy(txt_buf + pos, ins_txt, ins_len); +} + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len) +{ + + uint32_t old_len = strlen(txt); +#if LV_TXT_UTF8 != 0 + pos = lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/ + len = lv_txt_encoded_get_byte_id(&txt[pos], len); +#endif + + /*Copy the second part into the end to make place to text to insert*/ + uint32_t i; + for(i = pos; i <= old_len - len; i++) { + txt[i] = txt[i + len]; + } +} + + +/******************************* + * UTF-8 ENCODER/DECOER + ******************************/ + +#if LV_TXT_UTF8 + +/** + * Give the size of an UTF-8 coded character + * @param str pointer to a character in a string + * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code + */ +static uint8_t lv_txt_utf8_size(const char * str) +{ + if((str[0] & 0x80) == 0) return 1; + else if((str[0] & 0xE0) == 0xC0) return 2; + else if((str[0] & 0xF0) == 0xE0) return 3; + else if((str[0] & 0xF8) == 0xF0) return 4; + return 0; +} + + +/** + * Convert an Unicode letter to UTF-8. + * @param letter_uni an Unicode letter + * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű') + */ +static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni) +{ + if(letter_uni < 128) return letter_uni; + uint8_t bytes[4]; + + if(letter_uni < 0x0800) { + bytes[0] = ((letter_uni >> 6) & 0x1F) | 0xC0; + bytes[1] = ((letter_uni >> 0) & 0x3F) | 0x80; + bytes[2] = 0; + bytes[3] = 0; + } else if(letter_uni < 0x010000) { + bytes[0] = ((letter_uni >> 12) & 0x0F) | 0xE0; + bytes[1] = ((letter_uni >> 6) & 0x3F) | 0x80; + bytes[2] = ((letter_uni >> 0) & 0x3F) | 0x80; + bytes[3] = 0; + } else if(letter_uni < 0x110000) { + bytes[0] = ((letter_uni >> 18) & 0x07) | 0xF0; + bytes[1] = ((letter_uni >> 12) & 0x3F) | 0x80; + bytes[2] = ((letter_uni >> 6) & 0x3F) | 0x80; + bytes[3] = ((letter_uni >> 0) & 0x3F) | 0x80; + } + + uint32_t * res_p = (uint32_t *)bytes; + return *res_p; +} + +/** + * Convert a wide character, e.g. 'Á' little endian to be UTF-8 compatible + * @param c a wide character or a Little endian number + * @return `c` in big endian + */ +static uint32_t lv_txt_utf8_conv_wc(uint32_t c) +{ + /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/ + if((c & 0x80) != 0) { + uint32_t swapped; + uint8_t c8[4]; + memcpy(c8, &c, 4); + swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]); + uint8_t i; + for(i = 0; i < 4; i++) { + if((swapped & 0xFF) == 0) swapped = (swapped >> 8); /*Ignore leading zeros (they were in the end originally)*/ + } + c = swapped; + } + + return c; +} + +/** + * Decode an UTF-8 character from a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. + * After call it will point to the next UTF-8 char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i) +{ + /* Unicode to UTF-8 + * 00000000 00000000 00000000 0xxxxxxx -> 0xxxxxxx + * 00000000 00000000 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx + * 00000000 00000000 zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx + * 00000000 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx + * */ + + uint32_t result = 0; + + /*Dummy 'i' pointer is required*/ + uint32_t i_tmp = 0; + if(i == NULL) i = &i_tmp; + + /*Normal ASCII*/ + if((txt[*i] & 0x80) == 0) { + result = txt[*i]; + (*i)++; + } + /*Real UTF-8 decode*/ + else { + /*2 bytes UTF-8 code*/ + if((txt[*i] & 0xE0) == 0xC0) { + result = (uint32_t)(txt[*i] & 0x1F) << 6; + (*i)++; + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (txt[*i] & 0x3F); + (*i)++; + } + /*3 bytes UTF-8 code*/ + else if((txt[*i] & 0xF0) == 0xE0) { + result = (uint32_t)(txt[*i] & 0x0F) << 12; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 6; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (txt[*i] & 0x3F); + (*i)++; + } + /*4 bytes UTF-8 code*/ + else if((txt[*i] & 0xF8) == 0xF0) { + result = (uint32_t)(txt[*i] & 0x07) << 18; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 12; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 6; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += txt[*i] & 0x3F; + (*i)++; + } else { + (*i)++; /*Not UTF-8 char. Go the next.*/ + } + } + return result; +} + +/** + * Get previous UTF-8 character form a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'. + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i) +{ + uint8_t c_size; + uint8_t cnt = 0; + + /*Try to find a !0 long UTF-8 char by stepping one character back*/ + (*i)--; + do { + if(cnt >= 4) return 0; /*No UTF-8 char found before the initial*/ + + c_size = lv_txt_encoded_size(&txt[*i]); + if(c_size == 0) { + if(*i != 0)(*i)--; + else return 0; + } + cnt++; + } while(c_size == 0); + + uint32_t i_tmp = *i; + uint32_t letter = lv_txt_encoded_next(txt, &i_tmp); /*Character found, get it*/ + + return letter; + +} + +/** + * Convert a character index (in an UTF-8 text) to byte index. + * E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param utf8_id character index + * @return byte index of the 'utf8_id'th letter + */ +static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id) +{ + uint32_t i; + uint32_t byte_cnt = 0; + for(i = 0; i < utf8_id; i++) { + byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]); + } + + return byte_cnt; + +} + + +/** + * Convert a byte index (in an UTF-8 text) to character index. + * E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id) +{ + uint32_t i = 0; + uint32_t char_cnt = 0; + + while(i < byte_id) { + lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/ + char_cnt++; + } + + return char_cnt; +} + +/** + * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled. + * E.g.: "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +static uint32_t lv_txt_utf8_get_length(const char * txt) +{ +#if LV_TXT_UTF8 == 0 + return strlen(txt); +#else + uint32_t len = 0; + uint32_t i = 0; + + while(txt[i] != '\0') { + lv_txt_encoded_next(txt, &i); + len++; + } + + return len; +#endif +} + +#else +/** + * Give the size of an UTF-8 coded character + * @param str pointer to a character in a string + * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code + */ +static uint8_t lv_txt_ascii_size(const char * str) +{ + return 1; +} + + +/** + * Convert an Unicode letter to UTF-8. + * @param letter_uni an Unicode letter + * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű') + */ +static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni) +{ + if(letter_uni < 128) return letter_uni; + else return ' '; +} + +/** + * Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default. + * So this function does nothing just returns with `c`. + * @param c a character, e.g. 'A' + * @return same as `c` + */ +static uint32_t lv_txt_ascii_conv_wc(uint32_t c) +{ + return c; +} + +/** + * Decode an UTF-8 character from a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. + * After call it will point to the next UTF-8 char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i) +{ + if(i == NULL) return txt[1]; /*Get the next char */ + + uint8_t letter = txt[*i] ; + (*i)++; + return letter; +} + +/** + * Get previous UTF-8 character form a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'. + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i) +{ + if(i == NULL) return *(txt - 1); /*Get the prev. char */ + + (*i)--; + uint8_t letter = txt[*i] ; + + return letter; +} + +/** + * Convert a character index (in an UTF-8 text) to byte index. + * E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param utf8_id character index + * @return byte index of the 'utf8_id'th letter + */ +static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id) +{ + return utf8_id; /*In Non encoded no difference*/ +} + + +/** + * Convert a byte index (in an UTF-8 text) to character index. + * E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id) +{ + return byte_id; /*In Non encoded no difference*/ +} + +/** + * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled. + * E.g.: "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +static uint32_t lv_txt_ascii_get_length(const char * txt) +{ + return strlen(txt); +} +#endif +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Test if char is break char or not (a text can broken here or not) + * @param letter a letter + * @return false: 'letter' is not break char + */ +static bool is_break_char(uint32_t letter) +{ + uint8_t i; + bool ret = false; + + /*Compare the letter to TXT_BREAK_CHARS*/ + for(i = 0; LV_TXT_BREAK_CHARS[i] != '\0'; i++) { + if(letter == (uint32_t)LV_TXT_BREAK_CHARS[i]) { + ret = true; /*If match then it is break char*/ + break; + } + } + + return ret; +} + diff --git a/bdk/libs/lvgl/lv_misc/lv_txt.h b/bdk/libs/lvgl/lv_misc/lv_txt.h new file mode 100644 index 0000000..81b55f9 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_txt.h @@ -0,0 +1,197 @@ +/** + * @file lv_text.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_area.h" +#include "lv_font.h" +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_TXT_COLOR_CMD "#" + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_TXT_FLAG_NONE = 0x00, + LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/ + LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/ + LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/ +}; +typedef uint8_t lv_txt_flag_t; + +enum +{ + LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/ + LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/ + LV_TXT_CMD_STATE_IN, /*Processing the command*/ +}; +typedef uint8_t lv_txt_cmd_state_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag); + + +/** + * Check next character in a string and decide if te character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE + ***************************************************************/ + +/** + * Give the size of an encoded character + * @param str pointer to a character in a string + * @return length of the encoded character (1,2,3 ...). O in invalid + */ +extern uint8_t (*lv_txt_encoded_size)(const char *); + + +/** + * Convert an Unicode letter to encoded + * @param letter_uni an Unicode letter + * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü') + */ +extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t ); + +/** + * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c); + +/** + * Decode the next encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param i start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid data code + */ +extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * ); + +/** + * Get the previous encoded character form a string. + * @param txt pointer to '\0' terminated string + * @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'. + * @return the decoded Unicode character or 0 on invalid data + */ +extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); + +/** + * Convert a letter index (in an the encoded text) to byte index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param enc_id letter index + * @return byte index of the 'enc_id'th letter + */ +extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); + +/** + * Convert a byte index (in an encoded text) to character index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t); + +/** + * Get the number of characters (and NOT bytes) in a string. + * E.g. in UTF-8 "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +extern uint32_t (*lv_txt_get_encoded_length)(const char *); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_TXT*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_ufs.c b/bdk/libs/lvgl/lv_misc/lv_ufs.c new file mode 100644 index 0000000..ef1a165 --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_ufs.c @@ -0,0 +1,516 @@ +/** + * @file lv_ufs.c + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_ufs.h" +#if USE_LV_FILESYSTEM + +#include "lv_ll.h" +#include +#include +#include +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_ufs_ent_t * lv_ufs_ent_get(const char * fn); +static lv_ufs_ent_t * lv_ufs_ent_new(const char * fn); + +/********************** + * STATIC VARIABLES + **********************/ +static bool inited = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_file_ll), sizeof(lv_ufs_ent_t)); + + lv_fs_drv_t ufs_drv; + memset(&ufs_drv, 0, sizeof(lv_fs_drv_t)); /*Initialization*/ + + ufs_drv.file_size = sizeof(lv_ufs_file_t); + ufs_drv.rddir_size = sizeof(lv_ufs_dir_t); + ufs_drv.letter = UFS_LETTER; + ufs_drv.ready = lv_ufs_ready; + + ufs_drv.open = lv_ufs_open; + ufs_drv.close = lv_ufs_close; + ufs_drv.remove = lv_ufs_remove; + ufs_drv.read = lv_ufs_read; + ufs_drv.write = lv_ufs_write; + ufs_drv.seek = lv_ufs_seek; + ufs_drv.tell = lv_ufs_tell; + ufs_drv.size = lv_ufs_size; + ufs_drv.trunc = lv_ufs_trunc; + ufs_drv.free = lv_ufs_free; + + ufs_drv.dir_open = lv_ufs_dir_open; + ufs_drv.dir_read = lv_ufs_dir_read; + ufs_drv.dir_close = lv_ufs_dir_close; + + lv_fs_add_drv(&ufs_drv); + + inited = true; +} + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void) +{ + return inited; +} + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_open(void * file_p, const char * fn, lv_fs_mode_t mode) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = lv_ufs_ent_get(fn); + + fp->ent = NULL; + + /*If the file not exists ...*/ + if(ent == NULL) { + if((mode & LV_FS_MODE_WR) != 0) { /*Create the file if opened for write*/ + ent = lv_ufs_ent_new(fn); + if(ent == NULL) return LV_FS_RES_FULL; /*No space for the new file*/ + } else { + return LV_FS_RES_NOT_EX; /*Can not read not existing file*/ + } + } + + /*Can not write already opened and const data files*/ + if((mode & LV_FS_MODE_WR) != 0) { + if(ent->oc != 0) return LV_FS_RES_LOCKED; + if(ent->const_data != 0) return LV_FS_RES_DENIED; + } + + /*No error, the file can be opened*/ + fp->ent = ent; + fp->ar = mode & LV_FS_MODE_RD ? 1 : 0; + fp->aw = mode & LV_FS_MODE_WR ? 1 : 0; + fp->rwp = 0; + ent->oc ++; + + return LV_FS_RES_OK; +} + + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len) +{ + lv_ufs_file_t file; + lv_fs_res_t res; + + /*Error if the file already exists*/ + res = lv_ufs_open(&file, fn, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + lv_ufs_close(&file); + return LV_FS_RES_DENIED; + } + + lv_ufs_close(&file); + + res = lv_ufs_open(&file, fn, LV_FS_MODE_WR); + if(res != LV_FS_RES_OK) return res; + + lv_ufs_ent_t * ent = file.ent; + + if(ent->data_d != NULL) return LV_FS_RES_DENIED; + + ent->data_d = (void *) const_p; + ent->size = len; + ent->const_data = 1; + + res = lv_ufs_close(&file); + if(res != LV_FS_RES_OK) return res; + + return LV_FS_RES_OK; +} + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_close(void * file_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + if(fp->ent == NULL) return LV_FS_RES_OK; + + /*Decrement the Open counter*/ + if(fp->ent->oc > 0) { + fp->ent->oc--; + } + + return LV_FS_RES_OK; +} + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn) +{ + lv_ufs_ent_t * ent = lv_ufs_ent_get(fn); + if(ent == NULL) return LV_FS_RES_DENIED; /*File not exists*/ + + /*Can not be deleted is opened*/ + if(ent->oc != 0) return LV_FS_RES_DENIED; + + lv_ll_rem(&LV_GC_ROOT(_lv_file_ll), ent); + lv_mem_free(ent->fn_d); + ent->fn_d = NULL; + if(ent->const_data == 0) { + lv_mem_free(ent->data_d); + ent->data_d = NULL; + } + + lv_mem_free(ent); + + return LV_FS_RES_OK; +} + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_read(void * file_p, void * buf, uint32_t btr, uint32_t * br) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + lv_ufs_ent_t * ent = fp->ent; + *br = 0; + + if(ent->data_d == NULL || ent->size == 0) { /*Don't read empty files*/ + return LV_FS_RES_OK; + } else if(fp->ar == 0) { /*The file is not opened for read*/ + return LV_FS_RES_DENIED; + } + + /*No error, read the file*/ + if(fp->rwp + btr > ent->size) { /*Check too much bytes read*/ + *br = ent->size - fp->rwp; + } else { + *br = btr; + } + + /*Read the data*/ + uint8_t * data8_p; + if(ent->const_data == 0) { + data8_p = (uint8_t *) ent->data_d; + } else { + data8_p = ent->data_d; + } + + data8_p += fp->rwp; + memcpy(buf, data8_p, *br); + + fp->rwp += *br; /*Refresh the read write pointer*/ + + return LV_FS_RES_OK; +} + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_write(void * file_p, const void * buf, uint32_t btw, uint32_t * bw) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + *bw = 0; + + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + lv_ufs_ent_t * ent = fp->ent; + + /*Reallocate data array if it necessary*/ + uint32_t new_size = fp->rwp + btw; + if(new_size > ent->size) { + uint8_t * new_data = lv_mem_realloc(ent->data_d, new_size); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Cannot allocate the new memory*/ + + ent->data_d = new_data; + ent->size = new_size; + } + + /*Write the file*/ + uint8_t * data8_p = (uint8_t *) ent->data_d; + data8_p += fp->rwp; + memcpy(data8_p, buf, btw); + *bw = btw; + fp->rwp += *bw; + + return LV_FS_RES_OK; +} + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek(void * file_p, uint32_t pos) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + /*Simply move the rwp before EOF*/ + if(pos < ent->size) { + fp->rwp = pos; + } else { /*Expand the file size*/ + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + uint8_t * new_data = lv_mem_realloc(ent->data_d, pos); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/ + + ent->data_d = new_data; + ent->size = pos; + fp->rwp = pos; + } + + return LV_FS_RES_OK; +} + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell(void * file_p, uint32_t * pos_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + *pos_p = fp->rwp; + + return LV_FS_RES_OK; +} + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc(void * file_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + void * new_data = lv_mem_realloc(ent->data_d, fp->rwp); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/ + + ent->data_d = new_data; + ent->size = fp->rwp; + + return LV_FS_RES_OK; +} + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_size(void * file_p, uint32_t * size_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + *size_p = ent->size; + + return LV_FS_RES_OK; +} + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path) +{ + lv_ufs_dir_t * lv_ufs_rddir_p = rddir_p; + + lv_ufs_rddir_p->last_ent = NULL; + + if(path[0] != '\0') return LV_FS_RES_NOT_EX; /*Must be "" */ + else return LV_FS_RES_OK; +} + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn) +{ + lv_ufs_dir_t * ufs_dir_p = dir_p; + + if(ufs_dir_p->last_ent == NULL) { + ufs_dir_p->last_ent = lv_ll_get_head(&LV_GC_ROOT(_lv_file_ll)); + } else { + ufs_dir_p->last_ent = lv_ll_get_next(&LV_GC_ROOT(_lv_file_ll), ufs_dir_p->last_ent); + } + + if(ufs_dir_p->last_ent != NULL) { + strcpy(fn, ufs_dir_p->last_ent->fn_d); + } else { + fn[0] = '\0'; + } + + return LV_FS_RES_OK; +} + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p) +{ + (void)rddir_p; + return LV_FS_RES_OK; +} + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'lv_fs_res_t' + */ +lv_fs_res_t lv_ufs_free(uint32_t * total_p, uint32_t * free_p) +{ + +#if LV_MEM_CUSTOM == 0 + lv_mem_monitor_t mon; + + lv_mem_monitor(&mon); + *total_p = LV_MEM_SIZE >> 10; /*Convert bytes to kB*/ + *free_p = mon.free_size >> 10; +#else + *free_p = 0; +#endif + return LV_FS_RES_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Gives the lv_ufs_entry from a filename + * @param fn filename ('\0' terminated string) + * @return pointer to the dynamically allocated entry with 'fn' filename. + * NULL if no entry found with that name. + */ +static lv_ufs_ent_t * lv_ufs_ent_get(const char * fn) +{ + lv_ufs_ent_t * fp; + + LL_READ(LV_GC_ROOT(_lv_file_ll), fp) { + if(strcmp(fp->fn_d, fn) == 0) { + return fp; + } + } + + return NULL; +} + +/** + * Create a new entry with 'fn' filename + * @param fn filename ('\0' terminated string) + * @return pointer to the dynamically allocated new entry. + * NULL if no space for the entry. + */ +static lv_ufs_ent_t * lv_ufs_ent_new(const char * fn) +{ + lv_ufs_ent_t * new_ent = NULL; + new_ent = lv_ll_ins_head(&LV_GC_ROOT(_lv_file_ll)); /*Create a new file*/ + lv_mem_assert(new_ent); + if(new_ent == NULL) return NULL; + + new_ent->fn_d = lv_mem_alloc(strlen(fn) + 1); /*Save the name*/ + lv_mem_assert(new_ent->fn_d); + if(new_ent->fn_d == NULL) return NULL; + + strcpy(new_ent->fn_d, fn); + new_ent->data_d = NULL; + new_ent->size = 0; + new_ent->oc = 0; + new_ent->const_data = 0; + + return new_ent; +} + +#endif /*USE_LV_FILESYSTEM*/ + diff --git a/bdk/libs/lvgl/lv_misc/lv_ufs.h b/bdk/libs/lvgl/lv_misc/lv_ufs.h new file mode 100644 index 0000000..543104f --- /dev/null +++ b/bdk/libs/lvgl/lv_misc/lv_ufs.h @@ -0,0 +1,213 @@ +/** + * @file lv_ufs.h + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +#ifndef LV_UFS_H +#define LV_UFS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include "lv_fs.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define UFS_LETTER 'U' + +/********************** + * TYPEDEFS + **********************/ +/*Description of a file entry */ +typedef struct +{ + char * fn_d; + void * data_d; + uint32_t size; /*Data length in bytes*/ + uint16_t oc; /*Open Count*/ + uint8_t const_data :1; +} lv_ufs_ent_t; + +/*File descriptor, used to handle opening an entry more times simultaneously + Contains unique informations about the specific opening*/ +typedef struct +{ + lv_ufs_ent_t* ent; /*Pointer to the entry*/ + uint32_t rwp; /*Read Write Pointer*/ + uint8_t ar :1; /*1: Access for read is enabled */ + uint8_t aw :1; /*1: Access for write is enabled */ +} lv_ufs_file_t; + +/* Read directory descriptor. + * It is used to to iterate through the entries in a directory*/ +typedef struct +{ + lv_ufs_ent_t * last_ent; +} lv_ufs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void); + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void); + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode); + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len); + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_close (void * file_p); + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn); + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc (void * file_p); + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p); + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_read_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path); + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p); + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_arc.c b/bdk/libs/lvgl/lv_objx/lv_arc.c new file mode 100644 index 0000000..683d343 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_arc.c @@ -0,0 +1,310 @@ +/** + * @file lv_arc.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_arc.h" +#if USE_LV_ARC != 0 + +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_arc.h" +#include "../lv_themes/lv_theme.h" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a arc object + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + LV_LOG_TRACE("arc create started"); + + /*Create the ancestor of arc*/ + lv_obj_t * new_arc = lv_obj_create(par, copy); + lv_mem_assert(new_arc); + if(new_arc == NULL) return NULL; + + /*Allocate the arc type specific extended data*/ + lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(new_arc, sizeof(lv_arc_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_arc); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_arc); + + /*Initialize the allocated 'ext' */ + ext->angle_start = 45; + ext->angle_end = 315; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_arc, lv_arc_signal); + lv_obj_set_design_func(new_arc, lv_arc_design); + + /*Init the new arc arc*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, th->arc); + } else { + lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, &lv_style_plain_color); + } + + } + /*Copy an existing arc*/ + else { + lv_arc_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->angle_start = copy_ext->angle_start; + ext->angle_end = copy_ext->angle_end; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_arc); + } + + LV_LOG_INFO("arc created"); + + return new_arc; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + if(start > 360) start = 360; + if(end > 360) end = 360; + + ext->angle_start = start; + ext->angle_end = end; + + lv_obj_invalidate(arc); +} + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_ARC_STYLE_MAIN: + lv_obj_set_style(arc, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + return ext->angle_start; +} + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + return ext->angle_end; +} + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_ARC_STYLE_MAIN: + style = lv_obj_get_style(arc); + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the arcs + * @param arc pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + lv_style_t * style = lv_arc_get_style(arc, LV_ARC_STYLE_MAIN); + + lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(arc), lv_obj_get_height(arc))) / 2; + lv_coord_t x = arc->coords.x1 + lv_obj_get_width(arc) / 2; + lv_coord_t y = arc->coords.y1 + lv_obj_get_height(arc) / 2; + lv_opa_t opa_scale = lv_obj_get_opa_scale(arc); + lv_draw_arc(x, y, r, mask, ext->angle_start, ext->angle_end, style, opa_scale); + + + /*Draw circle on the ends if enabled */ + if(style->line.rounded) { + lv_coord_t thick_half = style->line.width / 2; + lv_coord_t cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_start) >> LV_TRIGO_SHIFT); + lv_coord_t cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_start + 90) >> LV_TRIGO_SHIFT); + + lv_style_t cir_style; + lv_style_copy(&cir_style, &lv_style_plain); + cir_style.body.grad_color = style->line.color; + cir_style.body.main_color = cir_style.body.grad_color; + cir_style.body.radius = LV_RADIUS_CIRCLE; + lv_area_t cir_area; + cir_area.x1 = cir_x + x - thick_half; + cir_area.y1 = cir_y + y - thick_half; + cir_area.x2 = cir_x + x + thick_half; + cir_area.y2 = cir_y + y + thick_half; + + lv_draw_rect(&cir_area, mask, &cir_style, opa_scale); + + cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_end) >> LV_TRIGO_SHIFT); + cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_end + 90) >> LV_TRIGO_SHIFT); + + cir_area.x1 = cir_x + x - thick_half; + cir_area.y1 = cir_y + y - thick_half; + cir_area.x2 = cir_x + x + thick_half; + cir_area.y2 = cir_y + y + thick_half; + + lv_draw_rect(&cir_area, mask, &cir_style, opa_scale); + } + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the arc + * @param arc pointer to a arc object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(arc, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_arc"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_arc.h b/bdk/libs/lvgl/lv_objx/lv_arc.h new file mode 100644 index 0000000..76231d8 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_arc.h @@ -0,0 +1,127 @@ +/** + * @file lv_arc.h + * + */ + + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ARC != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of arc*/ +typedef struct { + /*New data for this type */ + lv_coord_t angle_start; + lv_coord_t angle_end; +} lv_arc_ext_t; + + +/*Styles*/ +enum { + LV_ARC_STYLE_MAIN, +}; +typedef uint8_t lv_arc_style_t; + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a arc objects + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc); + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc); + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ARC*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ARC_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_bar.c b/bdk/libs/lvgl/lv_objx/lv_bar.c new file mode 100644 index 0000000..d83a609 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_bar.c @@ -0,0 +1,429 @@ + + +/** + * @file lv_bar.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_bar.h" +#if USE_LV_BAR != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("lv_bar create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_bar = lv_obj_create(par, copy); + lv_mem_assert(new_bar); + if(new_bar == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_bar); + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_bar); + + /*Allocate the object type specific extended data*/ + lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(new_bar, sizeof(lv_bar_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->min_value = 0; + ext->max_value = 100; + ext->cur_value = 0; + ext->sym = 0; + ext->style_indic = &lv_style_pretty_color; + + lv_obj_set_signal_func(new_bar, lv_bar_signal); + lv_obj_set_design_func(new_bar, lv_bar_design); + + /*Init the new bar object*/ + if(copy == NULL) { + lv_obj_set_click(new_bar, false); + lv_obj_set_size(new_bar, LV_DPI * 2, LV_DPI / 3); + lv_bar_set_value(new_bar, ext->cur_value); + + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_bar_set_style(new_bar, LV_BAR_STYLE_BG, th->bar.bg); + lv_bar_set_style(new_bar, LV_BAR_STYLE_INDIC, th->bar.indic); + } else { + lv_obj_set_style(new_bar, &lv_style_pretty); + } + } else { + lv_bar_ext_t * ext_copy = lv_obj_get_ext_attr(copy); + ext->min_value = ext_copy->min_value; + ext->max_value = ext_copy->max_value; + ext->cur_value = ext_copy->cur_value; + ext->style_indic = ext_copy->style_indic; + ext->sym = ext_copy->sym; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_bar); + + lv_bar_set_value(new_bar, ext->cur_value); + } + + LV_LOG_INFO("bar created"); + + return new_bar; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->cur_value == value) return; + + ext->cur_value = value > ext->max_value ? ext->max_value : value; + ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value; + lv_obj_invalidate(bar); +} + +#if USE_LV_ANIMATION +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->cur_value == value) return; + + int16_t new_value; + new_value = value > ext->max_value ? ext->max_value : value; + new_value = new_value < ext->min_value ? ext->min_value : new_value; + + lv_anim_t a; + a.var = bar; + a.start = ext->cur_value; + a.end = new_value; + a.fp = (lv_anim_fp_t)lv_bar_set_value; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + lv_anim_create(&a); +} +#endif + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->min_value == min && ext->max_value == max) return; + + ext->max_value = max; + ext->min_value = min; + if(ext->cur_value > max) { + ext->cur_value = max; + lv_bar_set_value(bar, ext->cur_value); + } + if(ext->cur_value < min) { + ext->cur_value = min; + lv_bar_set_value(bar, ext->cur_value); + } + lv_obj_invalidate(bar); +} + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + ext->sym = en ? 1 : 0; +} + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, lv_style_t * style) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + switch(type) { + case LV_BAR_STYLE_BG: + lv_obj_set_style(bar, style); + break; + case LV_BAR_STYLE_INDIC: + ext->style_indic = style; + lv_obj_refresh_ext_size(bar); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->cur_value; +} + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->min_value; +} + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->max_value; +} + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->sym ? true : false; +} + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t * bar, lv_bar_style_t type) +{ + lv_style_t * style = NULL; + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + switch(type) { + case LV_BAR_STYLE_BG: + style = lv_obj_get_style(bar); + break; + case LV_BAR_STYLE_INDIC: + style = ext->style_indic; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the bars + * @param bar pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask area*/ + return ancestor_design_f(bar, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(bar); + +#if USE_LV_GROUP == 0 + ancestor_design_f(bar, mask, mode); +#else + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(bar)) { + lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG); + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.border.width = 0; + lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale); + } else { + ancestor_design_f(bar, mask, mode); + } +#endif + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + if(ext->cur_value != ext->min_value || ext->sym) { + lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC); + lv_area_t indic_area; + lv_area_copy(&indic_area, &bar->coords); + indic_area.x1 += style_indic->body.padding.hor; + indic_area.x2 -= style_indic->body.padding.hor; + indic_area.y1 += style_indic->body.padding.ver; + indic_area.y2 -= style_indic->body.padding.ver; + + lv_coord_t w = lv_area_get_width(&indic_area); + lv_coord_t h = lv_area_get_height(&indic_area); + + if(w >= h) { + /*Horizontal*/ + indic_area.x2 = (int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value); + indic_area.x2 = indic_area.x1 + indic_area.x2 - 1; + + if(ext->sym && ext->min_value < 0 && ext->max_value > 0) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = indic_area.x1 + (-ext->min_value * w) / (ext->max_value - ext->min_value); + if(indic_area.x2 > zero) indic_area.x1 = zero; + else { + indic_area.x1 = indic_area.x2; + indic_area.x2 = zero; + } + } + } else { + indic_area.y1 = (int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value); + indic_area.y1 = indic_area.y2 - indic_area.y1 + 1; + + if(ext->sym && ext->min_value < 0 && ext->max_value > 0) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = indic_area.y2 - (-ext->min_value * h) / (ext->max_value - ext->min_value); + if(indic_area.y1 < zero) indic_area.y2 = zero; + else { + indic_area.y2 = indic_area.y1; + indic_area.y1 = zero; + } + } + } + + + /*Draw the indicator*/ + lv_draw_rect(&indic_area, mask, style_indic, opa_scale); + } + } else if(mode == LV_DESIGN_DRAW_POST) { +#if USE_LV_GROUP + /*Draw the border*/ + if(lv_obj_is_focused(bar)) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(bar); + lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG); + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.empty = 1; + style_tmp.body.shadow.width = 0; + lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale); + } +#endif + + } + return true; +} + +/** + * Signal function of the bar + * @param bar pointer to a bar object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(bar, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC); + if(style_indic->body.shadow.width > bar->ext_size) bar->ext_size = style_indic->body.shadow.width; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_bar"; + } + + return res; +} + + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_bar.h b/bdk/libs/lvgl/lv_objx/lv_bar.h new file mode 100644 index 0000000..2190384 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_bar.h @@ -0,0 +1,160 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BAR != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of bar*/ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + int16_t cur_value; /*Current value of the bar*/ + int16_t min_value; /*Minimum value of the bar*/ + int16_t max_value; /*Maximum value of the bar*/ + uint8_t sym :1; /*Symmetric: means the center is around zero value*/ + lv_style_t *style_indic; /*Style of the indicator*/ +} lv_bar_ext_t; + +enum { + LV_BAR_STYLE_BG, + LV_BAR_STYLE_INDIC, +}; +typedef uint8_t lv_bar_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value); + +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time); + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max); + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en); + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar); + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar); + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar); + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar); + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BAR_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_btn.c b/bdk/libs/lvgl/lv_objx/lv_btn.c new file mode 100644 index 0000000..f46250c --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_btn.c @@ -0,0 +1,763 @@ +/** + * @file lv_btn.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_btn.h" +#if USE_LV_BTN != 0 + +#include +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_BTN_INK_VALUE_MAX 256 +#define LV_BTN_INK_VALUE_MAX_SHIFT 8 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param); + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT +static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val); +static void lv_btn_ink_effect_anim_ready(void * p); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT +static lv_coord_t ink_act_value; +static lv_obj_t * ink_obj; +static lv_btn_state_t ink_bg_state; +static lv_btn_state_t ink_top_state; +static bool ink_ready; +static bool ink_playback; +static lv_point_t ink_point; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("button create started"); + + lv_obj_t * new_btn; + + new_btn = lv_cont_create(par, copy); + lv_mem_assert(new_btn); + if(new_btn == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btn); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_btn); + + /*Allocate the extended data*/ + lv_btn_ext_t * ext = lv_obj_allocate_ext_attr(new_btn, sizeof(lv_btn_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->state = LV_BTN_STATE_REL; + + ext->actions[LV_BTN_ACTION_PR] = NULL; + ext->actions[LV_BTN_ACTION_CLICK] = NULL; + ext->actions[LV_BTN_ACTION_LONG_PR] = NULL; + ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] = NULL; + + ext->styles[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles[LV_BTN_STATE_INA] = &lv_style_btn_ina; + + ext->long_pr_action_executed = 0; + ext->toggle = 0; + ext->idx = 0; +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ext->ink_in_time = 0; + ext->ink_wait_time = 0; + ext->ink_out_time = 0; +#endif + + lv_obj_set_signal_func(new_btn, lv_btn_signal); + lv_obj_set_design_func(new_btn, lv_btn_design); + + /*If no copy do the basic initialization*/ + if(copy == NULL) { + /*Set layout if the button is not a screen*/ + if(par != NULL) { + lv_btn_set_layout(new_btn, LV_LAYOUT_CENTER); + } + + lv_obj_set_click(new_btn, true); /*Be sure the button is clickable*/ + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_btn_set_style(new_btn, LV_BTN_STYLE_REL, th->btn.rel); + lv_btn_set_style(new_btn, LV_BTN_STYLE_PR, th->btn.pr); + lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_REL, th->btn.tgl_rel); + lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_PR, th->btn.tgl_pr); + lv_btn_set_style(new_btn, LV_BTN_STYLE_INA, th->btn.ina); + } else { + lv_obj_set_style(new_btn, ext->styles[LV_BTN_STATE_REL]); + } + } + /*Copy 'copy'*/ + else { + lv_btn_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->state = copy_ext->state; + ext->toggle = copy_ext->toggle; +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ext->ink_in_time = copy_ext->ink_in_time; + ext->ink_wait_time = copy_ext->ink_wait_time; + ext->ink_out_time = copy_ext->ink_out_time; +#endif + memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions)); + memcpy(ext->styles, copy_ext->styles, sizeof(ext->styles)); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_btn); + } + + LV_LOG_INFO("button created"); + + return new_btn; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + ext->toggle = tgl != false ? 1 : 0; +} + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + if(ext->state != state) { + ext->state = state; + lv_obj_set_style(btn, ext->styles[state]); + } +} + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + switch(ext->state) { + case LV_BTN_STATE_REL: + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + break; + case LV_BTN_STATE_PR: + lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR); + break; + case LV_BTN_STATE_TGL_REL: + lv_btn_set_state(btn, LV_BTN_STATE_REL); + break; + case LV_BTN_STATE_TGL_PR: + lv_btn_set_state(btn, LV_BTN_STATE_PR); + break; + default: + break; + } +} + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action) +{ + if(type >= LV_BTN_ACTION_NUM) return; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->actions[type] = action; +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_in_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_ink_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time) +{ + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_wait_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_wait_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_out_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_out_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set a style of a button + * @param btn pointer to a button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t * style) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + switch(type) { + case LV_BTN_STYLE_REL: + ext->styles[LV_BTN_STATE_REL] = style; + break; + case LV_BTN_STYLE_PR: + ext->styles[LV_BTN_STATE_PR] = style; + break; + case LV_BTN_STYLE_TGL_REL: + ext->styles[LV_BTN_STATE_TGL_REL] = style; + break; + case LV_BTN_STYLE_TGL_PR: + ext->styles[LV_BTN_STATE_TGL_PR] = style; + break; + case LV_BTN_STYLE_INA: + ext->styles[LV_BTN_STATE_INA] = style; + break; + } + + /*Refresh the object with the new style*/ + lv_obj_set_style(btn, ext->styles[ext->state]); +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->state; +} + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + return ext->toggle != 0 ? true : false; +} + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type) +{ + if(type >= LV_BTN_ACTION_NUM) return NULL; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->actions[type]; +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_in_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} + + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_wait_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_in_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} + +/** + * Get a style of a button + * @param btn pointer to a button object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type) +{ + lv_style_t * style = NULL; + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + switch(type) { + case LV_BTN_STYLE_REL: + style = ext->styles[LV_BTN_STATE_REL]; + break; + case LV_BTN_STYLE_PR: + style = ext->styles[LV_BTN_STATE_PR]; + break; + case LV_BTN_STYLE_TGL_REL: + style = ext->styles[LV_BTN_STATE_TGL_REL]; + break; + case LV_BTN_STYLE_TGL_PR: + style = ext->styles[LV_BTN_STATE_TGL_PR]; + break; + case LV_BTN_STYLE_INA: + style = ext->styles[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the drop down lists + * @param btn pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } else if(mode == LV_DESIGN_DRAW_MAIN) { + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + if(btn != ink_obj) { + ancestor_design(btn, mask, mode); + } else { + lv_opa_t opa_scale = lv_obj_get_opa_scale(btn); + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + /*Draw the normal button*/ + if(ink_playback == false) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, ext->styles[ink_bg_state]); + style_tmp.body.shadow.width = ext->styles[ink_top_state]->body.shadow.width; + lv_draw_rect(&btn->coords, mask, &style_tmp, opa_scale); + + lv_coord_t w = lv_obj_get_width(btn); + lv_coord_t h = lv_obj_get_height(btn); + lv_coord_t r_max = LV_MATH_MIN(w, h) / 2; + + /*In the first part of the animation increase the size of the circle (ink effect) */ + lv_area_t cir_area; + + lv_coord_t coord_state = ink_act_value < LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value : LV_BTN_INK_VALUE_MAX / 2; + lv_point_t p_act; + p_act.x = ink_point.x; + p_act.y = ink_point.y; + lv_coord_t x_err = (btn->coords.x1 + w / 2) - p_act.x; + lv_coord_t y_err = (btn->coords.y1 + h / 2) - p_act.y; + + p_act.x += (x_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1); + p_act.y += (y_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1); + + lv_coord_t half_side = LV_MATH_MAX(w, h) / 2; + cir_area.x1 = p_act.x - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.y1 = p_act.y - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.x2 = p_act.x + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.y2 = p_act.y + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + + lv_area_intersect(&cir_area, &btn->coords, &cir_area); /*Limit the area. (It might be too big on the smaller side)*/ + + /*In the second part animate the radius. Circle -> body.radius*/ + lv_coord_t r_state = ink_act_value > LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value - LV_BTN_INK_VALUE_MAX / 2 : 0; + + lv_style_copy(&style_tmp, ext->styles[ink_top_state]); + style_tmp.body.radius = r_max + (((ext->styles[ink_bg_state]->body.radius - r_max) * r_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + style_tmp.body.border.width = 0; + + /*Draw the circle*/ + lv_draw_rect(&cir_area, mask, &style_tmp, opa_scale); + } else { + lv_style_t res; + lv_style_copy(&res, ext->styles[ink_bg_state]); + lv_style_mix(ext->styles[ink_bg_state], ext->styles[ink_top_state], &res, ink_act_value); + lv_draw_rect(&btn->coords, mask, &res, opa_scale); + + } + } +#else + ancestor_design(btn, mask, mode); +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(btn, mask, mode); + } + + return true; +} + +/** + * Signal function of the button + * @param btn pointer to a button object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(btn, sign, param); + if(res != LV_RES_OK) return res; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + lv_btn_state_t state = lv_btn_get_state(btn); + bool tgl = lv_btn_get_toggle(btn); + + if(sign == LV_SIGNAL_PRESSED) { + /*Refresh the state*/ + if(ext->state == LV_BTN_STATE_REL) { + lv_btn_set_state(btn, LV_BTN_STATE_PR); +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ink_bg_state = LV_BTN_STATE_REL; + ink_top_state = LV_BTN_STATE_PR; +#endif + } else if(ext->state == LV_BTN_STATE_TGL_REL) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR); +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ink_bg_state = LV_BTN_STATE_TGL_REL; + ink_top_state = LV_BTN_STATE_TGL_PR; +#endif + } + + ext->long_pr_action_executed = 0; + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + /*Forget the old inked button*/ + if(ink_obj != NULL && ink_obj != btn) { + lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim); + lv_obj_invalidate(ink_obj); + ink_obj = NULL; + } + /*Save the new data for inking and start it's animation if enabled*/ + if(ext->ink_in_time > 0) { + ink_obj = btn; + ink_playback = false; + ink_ready = false; + lv_indev_get_point(lv_indev_get_act(), &ink_point); + + lv_anim_t a; + a.var = btn; + a.start = 0; + a.end = LV_BTN_INK_VALUE_MAX; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = 0; + a.time = ext->ink_in_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif + /*Call the press action, 'param' is the caller indev_proc*/ + if(ext->actions[LV_BTN_ACTION_PR] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_PR](btn); + } + } else if(sign == LV_SIGNAL_PRESS_LOST) { + /*Refresh the state*/ + if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(sign == LV_SIGNAL_PRESSING) { + /*When the button begins to drag revert pressed states to released*/ + if(lv_indev_is_dragging(param) != false) { + if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + } else if(sign == LV_SIGNAL_RELEASED) { + /*If not dragged and it was not long press action then + *change state and run the action*/ + if(lv_indev_is_dragging(param) == false && ext->long_pr_action_executed == 0) { + if(ext->state == LV_BTN_STATE_PR && tgl == false) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == false) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(ext->state == LV_BTN_STATE_PR && tgl == true) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == true) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } + + if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else { /*If dragged change back the state*/ + if(ext->state == LV_BTN_STATE_PR) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + } + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + /*Draw the toggled state in the inking instead*/ + if(ext->toggle) { + ink_top_state = ext->state; + } + /*If not a toggle button and the "IN" inking is ready then start an "OUT" inking*/ + else if(ink_ready && ext->ink_out_time > 0) { + ink_obj = btn; + ink_playback = true; /*It is the playback. If not set `lv_btn_ink_effect_anim_ready` will start its own playback*/ + lv_indev_get_point(lv_indev_get_act(), &ink_point); + + lv_anim_t a; + a.var = ink_obj; + a.start = LV_BTN_INK_VALUE_MAX; + a.end = 0; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = 0; + a.time = ext->ink_out_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif + } else if(sign == LV_SIGNAL_LONG_PRESS) { + if(ext->actions[LV_BTN_ACTION_LONG_PR] && state != LV_BTN_STATE_INA) { + ext->long_pr_action_executed = 1; + res = ext->actions[LV_BTN_ACTION_LONG_PR](btn); + } + } else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + if(ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT](btn); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_REL); + if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else if(c == LV_GROUP_KEY_ENTER) { + if(!ext->long_pr_action_executed) { + if(lv_btn_get_toggle(btn)) { + if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else { + if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } + if(res != LV_RES_INV) { + ext->long_pr_action_executed = 0; + } + } + } else if(sign == LV_SIGNAL_CLEANUP) { +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + if(btn == ink_obj) { + lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim); + ink_obj = NULL; + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_btn"; + } + + return res; +} + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + +/** + * The animator function of inking. CAlled to increase the radius of ink + * @param btn pointer to the animated button + * @param val the new radius + */ +static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val) +{ + if(btn) { + ink_act_value = val; + lv_obj_invalidate(btn); + } +} + +/** + * Called to clean up when the ink animation is ready + * @param p unused + */ +static void lv_btn_ink_effect_anim_ready(void * p) +{ + (void) p; /*Unused*/ + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(ink_obj); + lv_btn_state_t state = lv_btn_get_state(ink_obj); + + lv_obj_invalidate(ink_obj); + ink_ready = true; + + if((state == LV_BTN_STATE_REL || state == LV_BTN_STATE_TGL_REL) && ext->toggle == 0 && ink_playback == false) { + lv_anim_t a; + a.var = ink_obj; + a.start = LV_BTN_INK_VALUE_MAX; + a.end = 0; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = -ext->ink_wait_time; + a.time = ext->ink_out_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + + ink_playback = true; + } else { + ink_obj = NULL; + } +} +#endif /*USE_LV_ANIMATION*/ + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_btn.h b/bdk/libs/lvgl/lv_objx/lv_btn.h new file mode 100644 index 0000000..3a48b62 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_btn.h @@ -0,0 +1,280 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "../lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* Button states + * It can be used not only by buttons but other button-like objects too*/ +enum +{ + LV_BTN_STATE_REL, + LV_BTN_STATE_PR, + LV_BTN_STATE_TGL_REL, + LV_BTN_STATE_TGL_PR, + LV_BTN_STATE_INA, + LV_BTN_STATE_NUM, +}; +typedef uint8_t lv_btn_state_t; + +enum +{ + LV_BTN_ACTION_CLICK, + LV_BTN_ACTION_PR, + LV_BTN_ACTION_LONG_PR, + LV_BTN_ACTION_LONG_PR_REPEAT, + LV_BTN_ACTION_NUM, +}; +typedef uint8_t lv_btn_action_t; + + +/*Data of button*/ +typedef struct +{ + lv_cont_ext_t cont; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t actions[LV_BTN_ACTION_NUM]; + lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/ + lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/ + int idx; +#if LV_BTN_INK_EFFECT + uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/ + uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */ + uint16_t ink_out_time; /*[ms] Time of ink disappearing*/ +#endif + uint8_t toggle :1; /*1: Toggle enabled*/ + uint8_t long_pr_action_executed :1; /*1: Long press action executed (Handled by the library)*/ +} lv_btn_ext_t; + +/*Styles*/ +enum { + LV_BTN_STYLE_REL, + LV_BTN_STYLE_PR, + LV_BTN_STYLE_TGL_REL, + LV_BTN_STYLE_TGL_PR, + LV_BTN_STYLE_INA, +}; +typedef uint8_t lv_btn_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl); + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state); + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn); + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action); + +/** + * Set the layout on a button + * @param btn pointer to a button object + * @param layout a layout from 'lv_cont_layout_t' + */ +static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout) +{ + lv_cont_set_layout(btn, layout); +} + +/** + * Enable the horizontal or vertical fit. + * The button size will be set to involve the children horizontally or vertically. + * @param btn pointer to a button object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +static inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(btn, hor_en, ver_en); +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time); + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time); + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time); + +/** + * Set a style of a button. + * @param btn pointer to button object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn); + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn); + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type); + +/** + * Get the layout of a button + * @param btn pointer to button object + * @return the layout from 'lv_cont_layout_t' + */ +static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn) +{ + return lv_cont_get_layout(btn); +} + +/** + * Get horizontal fit enable attribute of a button + * @param btn pointer to a button object + * @return true: horizontal fit is enabled; false: disabled + */ +static inline bool lv_btn_get_hor_fit(const lv_obj_t * btn) +{ + return lv_cont_get_hor_fit(btn); +} + +/** + * Get vertical fit enable attribute of a container + * @param btn pointer to a button object + * @return true: vertical fit is enabled; false: disabled + */ +static inline bool lv_btn_get_ver_fit(const lv_obj_t * btn) +{ + return lv_cont_get_ver_fit(btn); +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn); + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn); + +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn); + +/** + * Get style of a button. + * @param btn pointer to button object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BUTTON*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTN_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_btnm.c b/bdk/libs/lvgl/lv_objx/lv_btnm.c new file mode 100644 index 0000000..68d04e1 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_btnm.c @@ -0,0 +1,881 @@ +/** + * @file lv_btnm.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_btnm.h" +#if USE_LV_BTNM != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_refr.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param); +static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode); +static uint8_t get_button_width(const char * btn_str); +static bool button_is_hidden(const char * btn_str); +static bool button_is_repeat_disabled(const char * btn_str); +static bool button_is_inactive(const char * btn_str); +const char * cut_ctrl_byte(const char * btn_str); +static uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p); +static uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id); +static void allocate_btn_areas(lv_obj_t * btnm, const char ** map); + +/********************** + * STATIC VARIABLES + **********************/ +static const char * lv_btnm_def_map[] = {"Btn1", "Btn2", "Btn3", "\n", + "\002Btn4", "Btn5", "" + }; + +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("button matrix create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_btnm = lv_obj_create(par, copy); + lv_mem_assert(new_btnm); + if(new_btnm == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btnm); + + /*Allocate the object type specific extended data*/ + lv_btnm_ext_t * ext = lv_obj_allocate_ext_attr(new_btnm, sizeof(lv_btnm_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->btn_cnt = 0; + ext->btn_id_pr = LV_BTNM_PR_NONE; + ext->btn_id_tgl = LV_BTNM_PR_NONE; + ext->button_areas = NULL; + ext->action = NULL; + ext->map_p = NULL; + ext->toggle = 0; + ext->recolor = 0; + ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_btnm); + + lv_obj_set_signal_func(new_btnm, lv_btnm_signal); + lv_obj_set_design_func(new_btnm, lv_btnm_design); + + /*Init the new button matrix object*/ + if(copy == NULL) { + lv_obj_set_size(new_btnm, LV_HOR_RES / 2, LV_VER_RES / 4); + lv_btnm_set_map(new_btnm, lv_btnm_def_map); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BG, th->btnm.bg); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_REL, th->btnm.btn.rel); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_PR, th->btnm.btn.pr); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_REL, th->btnm.btn.tgl_rel); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_PR, th->btnm.btn.tgl_pr); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_INA, th->btnm.btn.ina); + } else { + lv_obj_set_style(new_btnm, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_btnm_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + memcpy(ext->styles_btn, copy_ext->styles_btn, sizeof(ext->styles_btn)); + ext->action = copy_ext->action; + ext->toggle = copy_ext->toggle; + ext->btn_id_tgl = copy_ext->btn_id_tgl; + lv_btnm_set_map(new_btnm, lv_btnm_get_map(copy)); + } + + LV_LOG_INFO("button matrix created"); + + return new_btnm; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) (\24x) + * - bit 4: no repeat (on long press) (\22x) + * - bit 3: hidden (\21x) + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map) +{ + if(map == NULL) return; + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + ext->map_p = map; + + /*Analyze the map and create the required number of buttons*/ + allocate_btn_areas(btnm, map); + + /*Set size and positions of the buttons*/ + lv_style_t * style_bg = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + lv_coord_t max_w = lv_obj_get_width(btnm) - 2 * style_bg->body.padding.hor; + lv_coord_t max_h = lv_obj_get_height(btnm) - 2 * style_bg->body.padding.ver; + lv_coord_t act_y = style_bg->body.padding.ver; + + /*Count the lines to calculate button height*/ + uint8_t line_cnt = 1; + uint8_t li; + for(li = 0; strlen(map[li]) != 0; li++) { + if(strcmp(map[li], "\n") == 0) line_cnt ++; + } + + lv_coord_t btn_h = max_h - ((line_cnt - 1) * style_bg->body.padding.inner); + btn_h = btn_h / line_cnt; + btn_h --; /*-1 because e.g. height = 100 means 101 pixels (0..100)*/ + + /* Count the units and the buttons in a line + * (A button can be 1,2,3... unit wide)*/ + uint16_t unit_cnt; /*Number of units in a row*/ + uint16_t unit_act_cnt; /*Number of units currently put in a row*/ + uint16_t btn_cnt; /*Number of buttons in a row*/ + uint16_t i_tot = 0; /*Act. index in the str map*/ + uint16_t btn_i = 0; /*Act. index of button areas*/ + const char ** map_p_tmp = map; + + /*Count the units and the buttons in a line*/ + while(1) { + unit_cnt = 0; + btn_cnt = 0; + /*Count the buttons in a line*/ + while(strcmp(map_p_tmp[btn_cnt], "\n") != 0 && + strlen(map_p_tmp[btn_cnt]) != 0) { /*Check a line*/ + unit_cnt += get_button_width(map_p_tmp[btn_cnt]); + btn_cnt ++; + } + + /*Make sure the last row is at the bottom of 'btnm'*/ + if(map_p_tmp[btn_cnt][0] == '\0') { /*Last row?*/ + btn_h = max_h - act_y + style_bg->body.padding.ver - 1; + } + + /*Only deal with the non empty lines*/ + if(btn_cnt != 0) { + /*Calculate the width of all units*/ + lv_coord_t all_unit_w = max_w - ((btn_cnt - 1) * style_bg->body.padding.inner); + + /*Set the button size and positions and set the texts*/ + uint16_t i; + lv_coord_t act_x = style_bg->body.padding.hor; + lv_coord_t act_unit_w; + unit_act_cnt = 0; + for(i = 0; i < btn_cnt; i++) { + /* one_unit_w = all_unit_w / unit_cnt + * act_unit_w = one_unit_w * button_width + * do this two operations but the multiply first to divide a greater number */ + act_unit_w = (all_unit_w * get_button_width(map_p_tmp[i])) / unit_cnt; + act_unit_w --; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/ + + /*Always recalculate act_x because of rounding errors */ + act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + style_bg->body.padding.hor; + + /* Set the button's area. + * If inner padding is zero then use the prev. button x2 as x1 to avoid rounding errors*/ + if(style_bg->body.padding.inner == 0 && act_x != style_bg->body.padding.hor) { + lv_area_set(&ext->button_areas[btn_i], ext->button_areas[btn_i - 1].x2, act_y, + act_x + act_unit_w, act_y + btn_h); + } else { + lv_area_set(&ext->button_areas[btn_i], act_x, act_y, + act_x + act_unit_w, act_y + btn_h); + } + + unit_act_cnt += get_button_width(map_p_tmp[i]); + + i_tot ++; + btn_i ++; + } + } + act_y += btn_h + style_bg->body.padding.inner; + + + if(strlen(map_p_tmp[btn_cnt]) == 0) break; /*Break on end of map*/ + map_p_tmp = &map_p_tmp[btn_cnt + 1]; /*Set the map to the next line*/ + i_tot ++; /*Skip the '\n'*/ + } + + lv_obj_invalidate(btnm); +} + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param cb pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + ext->action = action; +} + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + ext->toggle = en == false ? 0 : 1; + if(ext->toggle != 0) { + if(id >= ext->btn_cnt) id = ext->btn_cnt - 1; + ext->btn_id_tgl = id; + } else { + ext->btn_id_tgl = LV_BTNM_PR_NONE; + } + + lv_obj_invalidate(btnm); +} + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, lv_style_t * style) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + switch(type) { + case LV_BTNM_STYLE_BG: + lv_obj_set_style(btnm, style); + break; + case LV_BTNM_STYLE_BTN_REL: + ext->styles_btn[LV_BTN_STATE_REL] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_PR: + ext->styles_btn[LV_BTN_STATE_PR] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_TGL_REL: + ext->styles_btn[LV_BTN_STATE_TGL_REL] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_TGL_PR: + ext->styles_btn[LV_BTN_STATE_TGL_PR] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_INA: + ext->styles_btn[LV_BTN_STATE_INA] = style; + lv_obj_invalidate(btnm); + break; + } +} + +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + ext->recolor = en; + lv_obj_invalidate(btnm); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->map_p; +} + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->action; +} + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->btn_id_pr; +} + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + if(ext->toggle == 0) return LV_BTNM_PR_NONE; + else return ext->btn_id_tgl; +} + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type) +{ + lv_style_t * style = NULL; + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + switch(type) { + case LV_BTNM_STYLE_BG: + style = lv_obj_get_style(btnm); + break; + case LV_BTNM_STYLE_BTN_REL: + style = ext->styles_btn[LV_BTN_STATE_REL]; + break; + case LV_BTNM_STYLE_BTN_PR: + style = ext->styles_btn[LV_BTN_STATE_PR]; + break; + case LV_BTNM_STYLE_BTN_TGL_REL: + style = ext->styles_btn[LV_BTN_STATE_TGL_REL]; + break; + case LV_BTNM_STYLE_BTN_TGL_PR: + style = ext->styles_btn[LV_BTN_STATE_TGL_PR]; + break; + case LV_BTNM_STYLE_BTN_INA: + style = ext->styles_btn[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} + +bool lv_btnm_get_recolor(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + return ext->recolor; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the button matrixs + * @param btnm pointer to a button matrix object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design_f(btnm, mask, mode); + /*Return false if the object is not covers the mask_p area*/ + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + ancestor_design_f(btnm, mask, mode); + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + lv_style_t * bg_style = lv_obj_get_style(btnm); + lv_style_t * btn_style; + lv_opa_t opa_scale = lv_obj_get_opa_scale(btnm); + + lv_area_t area_btnm; + lv_obj_get_coords(btnm, &area_btnm); + + lv_area_t area_tmp; + lv_coord_t btn_w; + lv_coord_t btn_h; + + uint16_t btn_i = 0; + uint16_t txt_i = 0; + lv_style_t style_tmp; + lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE; + + if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR; + + for(btn_i = 0; btn_i < ext->btn_cnt; btn_i ++, txt_i ++) { + /*Search the next valid text in the map*/ + while(strcmp(ext->map_p[txt_i], "\n") == 0) { + txt_i ++; + } + + /*Skip hidden buttons*/ + if(button_is_hidden(ext->map_p[txt_i])) continue; + + lv_area_copy(&area_tmp, &ext->button_areas[btn_i]); + area_tmp.x1 += area_btnm.x1; + area_tmp.y1 += area_btnm.y1; + area_tmp.x2 += area_btnm.x1; + area_tmp.y2 += area_btnm.y1; + + btn_w = lv_area_get_width(&area_tmp); + btn_h = lv_area_get_height(&area_tmp); + + /*Load the style*/ + if(button_is_inactive(ext->map_p[txt_i])) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_INA); + else if(btn_i != ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL); + else if(btn_i == ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_PR); + else if(btn_i != ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_REL); + else if(btn_i == ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_PR); + else btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL); /*Not possible option, just to be sure*/ + + lv_style_copy(&style_tmp, btn_style); + + /*Remove borders on the edges if `LV_BORDER_INTERNAL`*/ + if(style_tmp.body.border.part & LV_BORDER_INTERNAL) { + if(area_tmp.y1 == btnm->coords.y1 + bg_style->body.padding.ver) { + style_tmp.body.border.part &= ~LV_BORDER_TOP; + } + if(area_tmp.y2 == btnm->coords.y2 - bg_style->body.padding.ver) { + style_tmp.body.border.part &= ~LV_BORDER_BOTTOM; + } + + if(txt_i == 0) { + style_tmp.body.border.part &= ~LV_BORDER_LEFT; + } + else if(strcmp(ext->map_p[txt_i - 1],"\n") == 0) { + style_tmp.body.border.part &= ~LV_BORDER_LEFT; + } + + if(ext->map_p[txt_i + 1][0] == '\0' || strcmp(ext->map_p[txt_i + 1], "\n") == 0) { + style_tmp.body.border.part &= ~LV_BORDER_RIGHT; + } + } + lv_draw_rect(&area_tmp, mask, &style_tmp, opa_scale); + + /*Calculate the size of the text*/ + if(btn_style->glass) btn_style = bg_style; + const lv_font_t * font = btn_style->text.font; + lv_point_t txt_size; + lv_txt_get_size(&txt_size, ext->map_p[txt_i], font, + btn_style->text.letter_space, btn_style->text.line_space, + lv_area_get_width(&area_btnm), txt_flag); + + area_tmp.x1 += (btn_w - txt_size.x) / 2; + area_tmp.y1 += (btn_h - txt_size.y) / 2; + area_tmp.x2 = area_tmp.x1 + txt_size.x; + area_tmp.y2 = area_tmp.y1 + txt_size.y; + + lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL); + } + } + return true; +} + +/** + * Signal function of the button matrix + * @param btnm pointer to a button matrix object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(btnm, sign, param); + if(res != LV_RES_OK) return res; + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + lv_area_t btnm_area; + lv_area_t btn_area; + lv_point_t p; + if(sign == LV_SIGNAL_CLEANUP) { + lv_mem_free(ext->button_areas); + } else if(sign == LV_SIGNAL_STYLE_CHG || sign == LV_SIGNAL_CORD_CHG) { + lv_btnm_set_map(btnm, ext->map_p); + } else if(sign == LV_SIGNAL_PRESSING) { + uint16_t btn_pr; + /*Search the pressed area*/ + lv_indev_get_point(param, &p); + btn_pr = get_button_from_point(btnm, &p); + /*Invalidate to old and the new areas*/; + lv_obj_get_coords(btnm, &btnm_area); + if(btn_pr != ext->btn_id_pr) { + lv_indev_reset_lpr(param); + if(ext->btn_id_pr != LV_BTNM_PR_NONE) { + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + } + if(btn_pr != LV_BTNM_PR_NONE) { + lv_area_copy(&btn_area, &ext->button_areas[btn_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + } + } + + ext->btn_id_pr = btn_pr; + } + + else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + if(ext->action && ext->btn_id_pr != LV_BTNM_PR_NONE) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(txt_i != LV_BTNM_PR_NONE) { + if(button_is_repeat_disabled(ext->map_p[txt_i]) == false && + button_is_inactive(ext->map_p[txt_i]) == false) { + res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + } + } + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(ext->btn_id_pr != LV_BTNM_PR_NONE) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(button_is_inactive(ext->map_p[txt_i]) == false && txt_i != LV_BTNM_PR_NONE) { /*Ignore the inactive buttons anf click between the buttons*/ + if(ext->action) res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + if(res == LV_RES_OK) { + + /*Invalidate to old pressed area*/; + lv_obj_get_coords(btnm, &btnm_area); + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + + if(ext->toggle != 0) { + /*Invalidate to old toggled area*/; + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_tgl]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + ext->btn_id_tgl = ext->btn_id_pr; + + } + + #if USE_LV_GROUP + /*Leave the clicked button when releases if this not the focused object in a group*/ + lv_group_t * g = lv_obj_get_group(btnm); + if(lv_group_get_focused(g) != btnm) { + ext->btn_id_pr = LV_BTNM_PR_NONE; + } + #else + ext->btn_id_pr = LV_BTNM_PR_NONE; + #endif + + } + } + } + } else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_DEFOCUS) { + ext->btn_id_pr = LV_BTNM_PR_NONE; + lv_obj_invalidate(btnm); + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_indev_t * indev = lv_indev_get_act(); + lv_hal_indev_type_t indev_type = lv_indev_get_type(indev); + if(indev_type == LV_INDEV_TYPE_POINTER) { + /*Select the clicked button*/ + lv_point_t p1; + lv_indev_get_point(indev, &p1); + uint16_t btn_i = get_button_from_point(btnm, &p1); + ext->btn_id_pr = btn_i; + } else if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigation mode don't select any button but in edit mode select the fist*/ + if(lv_group_get_editing(lv_obj_get_group(btnm))) ext->btn_id_pr = 0; + else ext->btn_id_pr = LV_BTNM_PR_NONE; + } else { + ext->btn_id_pr = 0; + } +#else + ext->btn_id_pr = 0; +#endif + lv_obj_invalidate(btnm); + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT) { + if(ext->btn_id_pr == LV_BTNM_PR_NONE) ext->btn_id_pr = 0; + else ext->btn_id_pr++; + if(ext->btn_id_pr >= ext->btn_cnt - 1) ext->btn_id_pr = ext->btn_cnt - 1; + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_LEFT) { + if(ext->btn_id_pr == LV_BTNM_PR_NONE) ext->btn_id_pr = 0; + if(ext->btn_id_pr > 0) ext->btn_id_pr--; + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_DOWN) { + lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + /*Find the area below the the current*/ + if(ext->btn_id_pr == LV_BTNM_PR_NONE) { + ext->btn_id_pr = 0; + } else { + uint16_t area_below; + lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1); + + for(area_below = ext->btn_id_pr; area_below < ext->btn_cnt; area_below ++) { + if(ext->button_areas[area_below].y1 > ext->button_areas[ext->btn_id_pr].y1 && + pr_center >= ext->button_areas[area_below].x1 && + pr_center <= ext->button_areas[area_below].x2 + style->body.padding.hor) { + break; + } + } + + if(area_below < ext->btn_cnt) ext->btn_id_pr = area_below; + } + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_UP) { + lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + /*Find the area below the the current*/ + if(ext->btn_id_pr == LV_BTNM_PR_NONE) { + ext->btn_id_pr = 0; + } else { + int16_t area_above; + lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1); + + for(area_above = ext->btn_id_pr; area_above >= 0; area_above --) { + if(ext->button_areas[area_above].y1 < ext->button_areas[ext->btn_id_pr].y1 && + pr_center >= ext->button_areas[area_above].x1 - style->body.padding.hor && + pr_center <= ext->button_areas[area_above].x2) { + break; + } + } + if(area_above >= 0) ext->btn_id_pr = area_above; + + } + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_ENTER) { + if(ext->action != NULL) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(txt_i != LV_BTNM_PR_NONE) { + res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + } + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_btnm"; + } + + + return res; +} + +/** + * Create the required number of buttons according to a map + * @param btnm pointer to button matrix object + * @param map_p pointer to a string array + */ +static void allocate_btn_areas(lv_obj_t * btnm, const char ** map) +{ + /*Count the buttons in the map*/ + uint16_t btn_cnt = 0; + uint16_t i = 0; + while(strlen(map[i]) != 0) { + if(strcmp(map[i], "\n") != 0) { /*Do not count line breaks*/ + btn_cnt ++; + } + i++; + } + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + if(ext->button_areas != NULL) { + lv_mem_free(ext->button_areas); + ext->button_areas = NULL; + } + + ext->button_areas = lv_mem_alloc(sizeof(lv_area_t) * btn_cnt); + lv_mem_assert(ext->button_areas); + if(ext->button_areas == NULL) btn_cnt = 0; + + ext->btn_cnt = btn_cnt; +} + +/** + * Get the width of a button in units. It comes from the first "letter". + * @param btn_str The descriptor string of a button. E.g. "apple" or "\004banana" + * @return the width of the button in units + */ +static uint8_t get_button_width(const char * btn_str) +{ + if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) { + return btn_str[0] & LV_BTNM_WIDTH_MASK; + } + + return 1; /*Default width is 1*/ +} + +static bool button_is_hidden(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_HIDE_MASK)) { + return true; + } + + return false; +} + +static bool button_is_repeat_disabled(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_REPEAT_DISABLE_MASK)) { + return true; + } + + return false; +} + +static bool button_is_inactive(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_INACTIVE_MASK)) { + return true; + } + + return false; +} + + +const char * cut_ctrl_byte(const char * btn_str) +{ + /*Cut the control byte if present*/ + if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) return &btn_str[1]; + else return btn_str; +} + +/** + * Gives the button id of a button under a given point + * @param btnm pointer to a button matrix object + * @param p a point with absolute coordinates + * @return the id of the button or LV_BTNM_PR_NONE. + */ +static uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p) +{ + lv_area_t btnm_cords; + lv_area_t btn_area; + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + uint16_t i; + lv_obj_get_coords(btnm, &btnm_cords); + + for(i = 0; i < ext->btn_cnt; i++) { + lv_area_copy(&btn_area, &ext->button_areas[i]); + btn_area.x1 += btnm_cords.x1; + btn_area.y1 += btnm_cords.y1; + btn_area.x2 += btnm_cords.x1; + btn_area.y2 += btnm_cords.y1; + if(lv_area_is_point_on(&btn_area, p) != false) { + break; + } + } + + if(i == ext->btn_cnt) i = LV_BTNM_PR_NONE; + + return i; +} + +/** + * Get the text of a button + * @param btnm pointer to a button matrix object + * @param btn_id button id + * @return text id in ext->map_p or LV_BTNM_PR_NONE if 'btn_id' was invalid + */ +static uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + if(btn_id > ext->btn_cnt) return LV_BTNM_PR_NONE; + + uint16_t txt_i = 0; + uint16_t btn_i = 0; + + /* Search the text of ext->btn_pr the buttons text in the map + * Skip "\n"-s*/ + while(btn_i != btn_id) { + btn_i ++; + txt_i ++; + if(strcmp(ext->map_p[txt_i], "\n") == 0) txt_i ++; + } + + if(btn_i == ext->btn_cnt) return LV_BTNM_PR_NONE; + + return txt_i; +} + + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_btnm.h b/bdk/libs/lvgl/lv_objx/lv_btnm.h new file mode 100644 index 0000000..de334b7 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_btnm.h @@ -0,0 +1,197 @@ +/** + * @file lv_btnm.h + * + */ + + +#ifndef LV_BTNM_H +#define LV_BTNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BTNM != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_label.h" +#include "lv_btn.h" + +/********************* + * DEFINES + *********************/ + +/*Control byte*/ +#define LV_BTNM_CTRL_CODE 0x80 /*The control byte has to begin (if present) with 0b10xxxxxx*/ +#define LV_BTNM_CTRL_MASK 0xC0 +#define LV_BTNM_WIDTH_MASK 0x07 +#define LV_BTNM_HIDE_MASK 0x08 +#define LV_BTNM_REPEAT_DISABLE_MASK 0x10 +#define LV_BTNM_INACTIVE_MASK 0x20 + + +#define LV_BTNM_PR_NONE 0xFFFF +/********************** + * TYPEDEFS + **********************/ + +/* Type of callback function which is called when a button is released or long pressed on the button matrix + * Parameters: button matrix, text of the released button + * return LV_ACTION_RES_INV if the button matrix is deleted else LV_ACTION_RES_OK*/ +typedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt); + +/*Data of button matrix*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + const char ** map_p; /*Pointer to the current map*/ + lv_area_t *button_areas; /*Array of areas of buttons*/ + lv_btnm_action_t action; /*A function to call when a button is releases*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t btn_id_pr; /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/ + uint16_t btn_id_tgl; /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */ + uint8_t toggle :1; /*Enable toggling*/ + uint8_t recolor :1; /*Enable button recoloring*/ +} lv_btnm_ext_t; + +enum { + LV_BTNM_STYLE_BG, + LV_BTNM_STYLE_BTN_REL, + LV_BTNM_STYLE_BTN_PR, + LV_BTNM_STYLE_BTN_TGL_REL, + LV_BTNM_STYLE_BTN_TGL_PR, + LV_BTNM_STYLE_BTN_INA, +}; +typedef uint8_t lv_btnm_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) + * - bit 4: no repeat (on long press) + * - bit 3: hidden + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map); + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param action pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action); + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id); + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm); + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type); + +/** + * Find whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_btnm_get_recolor(const lv_obj_t * btnm); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BTNM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTNM_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_calendar.c b/bdk/libs/lvgl/lv_objx/lv_calendar.c new file mode 100644 index 0000000..50304c3 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_calendar.c @@ -0,0 +1,1038 @@ +/** + * @file lv_calendar.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_calendar.h" +#if USE_LV_CALENDAR != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_misc/lv_math.h" +#include "../lv_core/lv_indev.h" +#include "../lv_themes/lv_theme.h" +//#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +enum { + DAY_DRAW_PREV_MONTH, + DAY_DRAW_ACT_MONTH, + DAY_DRAW_NEXT_MONTH, +}; +typedef uint8_t day_draw_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param); +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point); +static lv_coord_t get_header_height(lv_obj_t * calendar); +static lv_coord_t get_day_names_height(lv_obj_t * calendar); +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_days(lv_obj_t * calendar, const lv_area_t * mask); +static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day); +static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day); +static const char * get_day_name(lv_obj_t * calendar, uint8_t day); +static const char * get_month_name(lv_obj_t * calendar, int32_t month); +static uint8_t get_month_length(int32_t year, int32_t month); +static uint8_t is_leap_year(uint32_t year); + + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; +static const char * day_name[7] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; +static const char * month_name[12] = {"January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" +}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a calendar object + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("calendar create started"); + + /*Create the ancestor of calendar*/ + lv_obj_t * new_calendar = lv_obj_create(par, copy); + lv_mem_assert(new_calendar); + if(new_calendar == NULL) return NULL; + + /*Allocate the calendar type specific extended data*/ + lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(new_calendar, sizeof(lv_calendar_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_calendar); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_calendar); + + /*Initialize the allocated 'ext' */ + ext->today.year = 2018; + ext->today.month = 1; + ext->today.day = 1; + + ext->showed_date.year = 2018; + ext->showed_date.month = 1; + ext->showed_date.day = 1; + + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + + ext->highlighted_dates = NULL; + ext->highlighted_dates_num = 0; + ext->day_names = NULL; + ext->month_names = NULL; + ext->actions[LV_CALENDAR_ACTION_PR] = NULL; + ext->actions[LV_CALENDAR_ACTION_CLICK] = NULL; + ext->actions[LV_CALENDAR_ACTION_LONG_PR] = NULL; + ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] = NULL; + ext->style_header = &lv_style_plain_color; + ext->style_header_pr = &lv_style_pretty_color; + ext->style_highlighted_days = &lv_style_plain_color; + ext->style_inactive_days = &lv_style_btn_ina; + ext->style_week_box = &lv_style_plain_color; + ext->style_today_box = &lv_style_pretty_color; + ext->style_day_names = &lv_style_pretty; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_calendar, lv_calendar_signal); + lv_obj_set_design_func(new_calendar, lv_calendar_design); + + /*Init the new calendar calendar*/ + if(copy == NULL) { + lv_obj_set_size(new_calendar, LV_DPI * 2, LV_DPI * 2); + lv_obj_set_style(new_calendar, &lv_style_pretty); + + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, th->calendar.bg); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, th->calendar.header); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, th->calendar.header_pr); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, th->calendar.day_names); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, th->calendar.week_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, th->calendar.today_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, th->calendar.highlighted_days); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, th->calendar.inactive_days); + } else { + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, &lv_style_pretty); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, ext->style_header); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, ext->style_header_pr); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, ext->style_day_names); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, ext->style_week_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, ext->style_today_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, ext->style_highlighted_days); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, ext->style_inactive_days); + + } + + } + /*Copy an existing calendar*/ + else { + lv_calendar_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->today.year = copy_ext->today.year; + ext->today.month = copy_ext->today.month; + ext->today.day = copy_ext->today.day; + + ext->showed_date.year = copy_ext->showed_date.year; + ext->showed_date.month = copy_ext->showed_date.month; + ext->showed_date.day = copy_ext->showed_date.day; + + ext->highlighted_dates = copy_ext->highlighted_dates; + ext->highlighted_dates_num = copy_ext->highlighted_dates_num; + ext->day_names = copy_ext->day_names; + + memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions)); + + ext->month_names = copy_ext->month_names; + ext->style_header = copy_ext->style_header; + ext->style_header_pr = copy_ext->style_header_pr; + ext->style_highlighted_days = copy_ext->style_highlighted_days; + ext->style_inactive_days = copy_ext->style_inactive_days; + ext->style_week_box = copy_ext->style_week_box; + ext->style_today_box = copy_ext->style_today_box; + ext->style_day_names = copy_ext->style_day_names; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_calendar); + } + + LV_LOG_INFO("calendar created"); + + return new_calendar; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action) +{ + if(type >= LV_CALENDAR_ACTION_NUM) return; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->actions[type] = action; +} + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->today.year = today->year; + ext->today.month = today->month; + ext->today.day = today->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->showed_date.year = showed->year; + ext->showed_date.month = showed->month; + ext->showed_date.day = showed->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->highlighted_dates = highlighted; + ext->highlighted_dates_num = date_num; + + lv_obj_invalidate(calendar); +} + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->day_names = day_names; + lv_obj_invalidate(calendar); +} + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->month_names = day_names; + lv_obj_invalidate(calendar); +} + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t * style) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + switch(type) { + case LV_CALENDAR_STYLE_BG: + lv_obj_set_style(calendar, style); + break; + case LV_CALENDAR_STYLE_DAY_NAMES: + ext->style_day_names = style; + break; + case LV_CALENDAR_STYLE_HEADER: + ext->style_header = style; + break; + case LV_CALENDAR_STYLE_HEADER_PR: + ext->style_header_pr = style; + break; + case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS: + ext->style_highlighted_days = style; + break; + case LV_CALENDAR_STYLE_INACTIVE_DAYS: + ext->style_inactive_days = style; + break; + case LV_CALENDAR_STYLE_TODAY_BOX: + ext->style_today_box = style; + break; + case LV_CALENDAR_STYLE_WEEK_BOX: + ext->style_week_box = style; + break; + } + + lv_obj_invalidate(calendar); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type) +{ + if(type >= LV_CALENDAR_ACTION_NUM) return NULL; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->actions[type]; +} + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->today; +} + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->showed_date; +} + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->pressed_date; +} + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates; +} + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates_num; +} + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->day_names; +} + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->month_names; +} + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type) +{ + lv_style_t * style = NULL; + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + switch(type) { + case LV_CALENDAR_STYLE_BG: + style = lv_obj_get_style(calendar); + break; + case LV_CALENDAR_STYLE_HEADER: + style = ext->style_header; + break; + case LV_CALENDAR_STYLE_HEADER_PR: + style = ext->style_header_pr; + break; + case LV_CALENDAR_STYLE_DAY_NAMES: + style = ext->style_day_names; + break; + case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS: + style = ext->style_highlighted_days; + break; + case LV_CALENDAR_STYLE_INACTIVE_DAYS: + style = ext->style_inactive_days; + break; + case LV_CALENDAR_STYLE_WEEK_BOX: + style = ext->style_week_box; + break; + case LV_CALENDAR_STYLE_TODAY_BOX: + style = ext->style_today_box; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the calendars + * @param calendar pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + lv_draw_rect(&calendar->coords, mask, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG), opa_scale); + + draw_header(calendar, mask); + draw_day_names(calendar, mask); + draw_days(calendar, mask); + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the calendar + * @param calendar pointer to a calendar object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(calendar, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_PRESSED) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + /*Call the press action, 'param' is the caller indev_proc*/ + if(ext->actions[LV_CALENDAR_ACTION_PR]) { + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + + if(calculate_touched_day(calendar, &p)){ + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + res = ext->actions[LV_CALENDAR_ACTION_PR](calendar); + } + } + } else if(sign == LV_SIGNAL_PRESSING) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_area_t header_area; + lv_area_copy(&header_area, &calendar->coords); + header_area.y2 = header_area.y1 + get_header_height(calendar); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + + if(lv_area_is_point_on(&header_area, &p)) { + if(p.x < header_area.x1 + lv_area_get_width(&header_area) / 2) { + if(ext->btn_pressing != -1) lv_obj_invalidate(calendar); + ext->btn_pressing = -1; + } else { + if(ext->btn_pressing != 1) lv_obj_invalidate(calendar); + ext->btn_pressing = 1; + } + + ext->pressed_date.year = 0; + } else if(calculate_touched_day(calendar, &p)) { + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + } else { + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + ext->pressed_date.year = 0; + } + } else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->pressed_date.year = 0; + ext->btn_pressing = 0; + lv_obj_invalidate(calendar); + + } else if(sign == LV_SIGNAL_RELEASED) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->btn_pressing < 0) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year --; + } else { + ext->showed_date.month --; + } + } else if(ext->btn_pressing > 0) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year ++; + } else { + ext->showed_date.month ++; + } + } + else if(ext->pressed_date.year != 0) + { + if(ext->actions[LV_CALENDAR_ACTION_CLICK]) { + res = ext->actions[LV_CALENDAR_ACTION_CLICK](calendar); + } + } + + ext->pressed_date.year = 0; + ext->btn_pressing = 0; + lv_obj_invalidate(calendar); + + + } else if(sign == LV_SIGNAL_LONG_PRESS) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->actions[LV_CALENDAR_ACTION_LONG_PR] && (ext->pressed_date.year != 0)) { + res = ext->actions[LV_CALENDAR_ACTION_LONG_PR](calendar); + } + } else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] && (ext->pressed_date.year != 0)) { + res = ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT](calendar); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + uint8_t c = *((uint8_t *) param); + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year ++; + } else { + ext->showed_date.month ++; + } + lv_obj_invalidate(calendar); + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year --; + } else { + ext->showed_date.month --; + } + lv_obj_invalidate(calendar); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set date*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_calendar"; + } + + return res; +} + +/** + * It will check if the days part of calendar is touched + * and if it is, it will calculate the day and put it in pressed_date of calendar object. + * @param calendar pointer to a calendar object + * @param pointer to a point + * @return true: days part of calendar is touched and its related date is put in pressed date + * false: the point is out of days part area. + */ +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point) +{ + lv_area_t days_area; + lv_area_copy(&days_area, &calendar->coords); + lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG); + days_area.x1 += style_bg->body.padding.hor; + days_area.x2 -= style_bg->body.padding.hor; + days_area.y1 = calendar->coords.y1 + get_header_height(calendar) + get_day_names_height(calendar) - style_bg->body.padding.ver; + + if(lv_area_is_point_on(&days_area, touched_point)) { + lv_coord_t w = (days_area.x2 - days_area.x1 + 1) / 7; + lv_coord_t h = (days_area.y2 - days_area.y1 + 1) / 6; + uint8_t x_pos = 0; + x_pos = (touched_point->x - days_area.x1) / w; + if(x_pos > 6) x_pos = 6; + uint8_t y_pos = 0; + y_pos = (touched_point->y - days_area.y1) / h; + if(y_pos > 5) y_pos = 5; + + uint8_t i_pos = 0; + i_pos = (y_pos * 7) + x_pos; + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(i_pos < get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) ) { + ext->pressed_date.year = ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 1 ? 12 : (ext->showed_date.month - 1); + ext->pressed_date.day = get_month_length(ext->pressed_date.year, ext->pressed_date.month) - + get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + 1 + i_pos; + } + else if(i_pos < (get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + + get_month_length(ext->showed_date.year, ext->showed_date.month))) { + ext->pressed_date.year = ext->showed_date.year; + ext->pressed_date.month = ext->showed_date.month; + ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + } + else if(i_pos < 42) { + ext->pressed_date.year = ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 12 ? 1 : (ext->showed_date.month + 1); + ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + - get_month_length(ext->showed_date.year, ext->showed_date.month); + } + return true; + }else { + return false; + } +} + +/** + * Get the height of a calendar's header based on it's style + * @param calendar point to a calendar + * @return the header's height + */ +static lv_coord_t get_header_height(lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + return lv_font_get_height(ext->style_header->text.font) + ext->style_header->body.padding.ver * 2; +} + +/** + * Get the height of a calendar's day_names based on it's style + * @param calendar point to a calendar + * @return the day_names's height + */ +static lv_coord_t get_day_names_height(lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + return lv_font_get_height(ext->style_day_names->text.font) + ext->style_day_names->body.padding.ver * 2; +} + +/** + * Draw the calendar header with month name and arrows + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + + lv_area_t header_area; + header_area.x1 = calendar->coords.x1; + header_area.x2 = calendar->coords.x2; + header_area.y1 = calendar->coords.y1; + header_area.y2 = calendar->coords.y1 + get_header_height(calendar); + + lv_draw_rect(&header_area, mask, ext->style_header, opa_scale); + + /*Add the year + month name*/ + char txt_buf[64]; + lv_math_num_to_str(ext->showed_date.year, txt_buf); + txt_buf[4] = ' '; + txt_buf[5] = '\0'; + strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month)); + header_area.y1 += ext->style_header->body.padding.ver; + lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL); + + /*Add the left arrow*/ + lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header; + header_area.x1 += ext->style_header->body.padding.hor; + lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL); + + /*Add the right arrow*/ + arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header; + header_area.x1 = header_area.x2 - ext->style_header->body.padding.hor - + lv_txt_get_width(SYMBOL_RIGHT, strlen(SYMBOL_RIGHT), arrow_style->text.font, + arrow_style->text.line_space, LV_TXT_FLAG_NONE); + lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL); + +} + +/** + * Draw the day's name below the header + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + + lv_coord_t hpad = ext->style_day_names->body.padding.hor; + lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad; + lv_coord_t box_w = w / 7; + lv_area_t label_area; + label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + ext->style_day_names->body.padding.ver; + label_area.y2 = label_area.y1 + lv_font_get_height(ext->style_day_names->text.font); + uint32_t i; + for(i = 0; i < 7; i++) { + label_area.x1 = calendar->coords.x1 + (w * i) / 7 + hpad; + label_area.x2 = label_area.x1 + box_w; + lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER, NULL); + } + +} + +/** + * Draw the date numbers in a matrix + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_days(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG); + lv_coord_t hpad = style_bg->body.padding.hor; + lv_area_t label_area; + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + + ext->style_day_names->body.padding.ver + lv_font_get_height(ext->style_day_names->text.font) + + ext->style_day_names->body.padding.ver; + label_area.y2 = label_area.y1 + lv_font_get_height(style_bg->text.font); + + lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad; + lv_coord_t h = calendar->coords.y2 - label_area.y1 - style_bg->body.padding.ver; + lv_coord_t box_w = w / 7; + lv_coord_t vert_space = (h - (6 * lv_font_get_height(style_bg->text.font))) / 5; + + uint32_t week; + uint8_t day_cnt; + uint8_t month_start_day = get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + day_draw_state_t draw_state; /*true: Not the prev. or next month is drawn*/ + lv_style_t * act_style; + + /*If starting with the first day of the week then the previous month is not visible*/ + if(month_start_day == 0) { + day_cnt = 1; + draw_state = DAY_DRAW_ACT_MONTH; + act_style = style_bg; + } else { + draw_state = DAY_DRAW_PREV_MONTH; + day_cnt = get_month_length(ext->showed_date.year, ext->showed_date.month - 1); /*Length of the previous month*/ + day_cnt -= month_start_day - 1; /*First visible number of the previous month*/ + act_style = ext->style_inactive_days; + } + + + bool month_of_today_shown = false; + if(ext->showed_date.year == ext->today.year && + ext->showed_date.month == ext->today.month) { + month_of_today_shown = true; + } + + char buf[3]; + bool in_week_box = false; + + /*Draw 6 weeks*/ + for(week = 0; week < 6; week++) { + + /*Draw the "week box"*/ + if(month_of_today_shown && + ((draw_state == DAY_DRAW_ACT_MONTH && ext->today.day >= day_cnt && ext->today.day < day_cnt + 7) || + (draw_state == DAY_DRAW_PREV_MONTH && ext->today.day <= 7 - month_start_day && week == 0))) { + lv_area_t week_box_area; + lv_area_copy(&week_box_area, &label_area); /*'label_area' is already set for this row*/ + week_box_area.x1 = calendar->coords.x1 + style_bg->body.padding.hor - ext->style_week_box->body.padding.hor; + week_box_area.x2 = calendar->coords.x2 - style_bg->body.padding.hor + ext->style_week_box->body.padding.hor; + + week_box_area.y1 -= ext->style_week_box->body.padding.ver; + week_box_area.y2 += ext->style_week_box->body.padding.ver; + lv_draw_rect(&week_box_area, mask, ext->style_week_box, opa_scale); + + in_week_box = true; + } else { + in_week_box = false; + } + + /*Draw the 7 days of a week*/ + uint32_t day; + for(day = 0; day < 7; day++) { + /*The previous month is over*/ + if(draw_state == DAY_DRAW_PREV_MONTH && day == month_start_day) { + draw_state = DAY_DRAW_ACT_MONTH; + day_cnt = 1; + act_style = style_bg; + } + /*The current month is over*/ + if(draw_state == DAY_DRAW_ACT_MONTH && + day_cnt > get_month_length(ext->showed_date.year, ext->showed_date.month)) { + draw_state = DAY_DRAW_NEXT_MONTH; + day_cnt = 1; + act_style = ext->style_inactive_days; + } + + label_area.x1 = calendar->coords.x1 + (w * day) / 7 + hpad; + label_area.x2 = label_area.x1 + box_w; + + /*Draw the "today box"*/ + if(draw_state == DAY_DRAW_ACT_MONTH && month_of_today_shown && ext->today.day == day_cnt) { + lv_area_t today_box_area; + lv_area_copy(&today_box_area, &label_area); + today_box_area.x1 = label_area.x1; + today_box_area.x2 = label_area.x2; + + today_box_area.y1 = label_area.y1 - ext->style_today_box->body.padding.ver; + today_box_area.y2 = label_area.y2 + ext->style_today_box->body.padding.ver; + lv_draw_rect(&today_box_area, mask, ext->style_today_box, opa_scale); + } + + /*Get the final style : highlighted/week box/today box/normal*/ + lv_style_t * final_style; + if(draw_state == DAY_DRAW_PREV_MONTH && + is_highlighted(calendar, ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0), + ext->showed_date.month == 1 ? 12 : ext->showed_date.month - 1, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(draw_state == DAY_DRAW_ACT_MONTH && + is_highlighted(calendar, ext->showed_date.year, + ext->showed_date.month, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(draw_state == DAY_DRAW_NEXT_MONTH && + is_highlighted(calendar, ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0), + ext->showed_date.month == 12 ? 1 : ext->showed_date.month + 1, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(month_of_today_shown && day_cnt == ext->today.day && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_today_box; + else if(in_week_box && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_week_box; + else final_style = act_style; + + /*Write the day's number*/ + lv_math_num_to_str(day_cnt, buf); + lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL); + + /*Go to the next day*/ + day_cnt ++; + + } + + /*Got to the next weeks row*/ + label_area.y1 += vert_space + lv_font_get_height(style_bg->text.font); + label_area.y2 += vert_space + lv_font_get_height(style_bg->text.font); + } +} + +/** + * Check weather a date is highlighted or not + * @param calendar pointer to a calendar object + * @param year a year + * @param month a month [1..12] + * @param day a day [1..31] + * @return true: highlighted + */ +static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + if(ext->highlighted_dates == NULL || ext->highlighted_dates_num == 0) return false; + + uint32_t i; + for(i = 0; i < ext->highlighted_dates_num; i++) { + if(ext->highlighted_dates[i].year == year && + ext->highlighted_dates[i].month == month && + ext->highlighted_dates[i].day == day) { + return true; + } + } + + return false; +} + +/** + * Get the day name + * @param calendar pointer to a calendar object + * @param day a day in [0..6] + * @return + */ +static const char * get_day_name(lv_obj_t * calendar, uint8_t day) +{ + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->day_names) return ext->day_names[day]; + else return day_name[day]; +} + +/** + * Get the month name + * @param calendar pointer to a calendar object + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year + * @return + */ +static const char * get_month_name(lv_obj_t * calendar, int32_t month) +{ + month --; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) month = 12 + month; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->month_names) return ext->month_names[month]; + else return month_name[month]; +} + +/** + * Get the number of days in a month + * @param year a year + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year + * @return [28..31] + */ +static uint8_t get_month_length(int32_t year, int32_t month) +{ + month --; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) { + year--; /*Already in the previous year (won't be less then -12 to skip a whole year)*/ + month = 12 + month; /*`month` is negative, the result will be < 12*/ + } + if(month >= 12) { + year ++; + month -= 12; + } + + /*month == 1 is february*/ + return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2; + + +} + +/** + * Tells whether a year is leap year or not + * @param year a year + * @return 0: not leap year; 1: leap year + */ +static uint8_t is_leap_year(uint32_t year) +{ + return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1; +} + +/** + * Get the day of the week + * @param year a year + * @param month a month + * @param day a day + * @return [0..6] which means [Sun..Sat] + */ +static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day) +{ + uint32_t a = month < 3 ? 1 : 0; + uint32_t b = year - a; + + uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + + b + (b / 4) - (b / 100) + (b / 400)) % 7; + + return day_of_week; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_calendar.h b/bdk/libs/lvgl/lv_objx/lv_calendar.h new file mode 100644 index 0000000..e573ae5 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_calendar.h @@ -0,0 +1,246 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CALENDAR != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +enum +{ + LV_CALENDAR_ACTION_CLICK, + LV_CALENDAR_ACTION_PR, + LV_CALENDAR_ACTION_LONG_PR, + LV_CALENDAR_ACTION_LONG_PR_REPEAT, + LV_CALENDAR_ACTION_NUM, +}; +typedef uint8_t lv_calendar_action_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/ + uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + lv_action_t actions[LV_CALENDAR_ACTION_NUM]; + + /*Styles*/ + lv_style_t * style_header; + lv_style_t * style_header_pr; + lv_style_t * style_day_names; + lv_style_t * style_highlighted_days; + lv_style_t * style_inactive_days; + lv_style_t * style_week_box; + lv_style_t * style_today_box; +} lv_calendar_ext_t; + +/*Styles*/ +enum { + LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/ + LV_CALENDAR_STYLE_HEADER, + LV_CALENDAR_STYLE_HEADER_PR, + LV_CALENDAR_STYLE_DAY_NAMES, + LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, + LV_CALENDAR_STYLE_INACTIVE_DAYS, + LV_CALENDAR_STYLE_WEEK_BOX, + LV_CALENDAR_STYLE_TODAY_BOX, +}; +typedef uint8_t lv_calendar_style_t; + + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action); + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num); + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type); + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_canvas.c b/bdk/libs/lvgl/lv_objx/lv_canvas.c new file mode 100644 index 0000000..0c6d9dd --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_canvas.c @@ -0,0 +1,593 @@ +/** + * @file lv_canvas.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_canvas.h" +#if USE_LV_CANVAS != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("canvas create started"); + + /*Create the ancestor of canvas*/ + lv_obj_t * new_canvas = lv_img_create(par, copy); + lv_mem_assert(new_canvas); + if(new_canvas == NULL) return NULL; + + /*Allocate the canvas type specific extended data*/ + lv_canvas_ext_t * ext = lv_obj_allocate_ext_attr(new_canvas, sizeof(lv_canvas_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_canvas); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_canvas); + + /*Initialize the allocated 'ext' */ + ext->dsc.header.always_zero = 0; + ext->dsc.header.cf = LV_IMG_CF_TRUE_COLOR; + ext->dsc.header.h = 0; + ext->dsc.header.w = 0; + ext->dsc.data_size = 0; + ext->dsc.data = NULL; + + lv_img_set_src(new_canvas, &ext->dsc); + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_canvas, lv_canvas_signal); + + /*Init the new canvas canvas*/ + if(copy == NULL) { + + } + /*Copy an existing canvas*/ + else { + //lv_canvas_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_canvas); + } + + LV_LOG_INFO("canvas created"); + + return new_canvas; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + * + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + + ext->dsc.header.cf = cf; + ext->dsc.header.w = w; + ext->dsc.header.h = h; + ext->dsc.data = buf; + ext->dsc.data_size = (lv_img_color_format_get_px_size(cf) * w * h) / 8; + + lv_img_set_src(canvas, &ext->dsc); +} +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c) +{ + + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_set_px: x or y out of the canvas"); + return; + } + + uint8_t * buf_u8 = (uint8_t *) ext->dsc.data; + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR || + ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t); + + memcpy(&buf_u8[px], &c, sizeof(lv_color_t)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += 4 * 2; + uint8_t bit = x & 0x7; + x = x >> 3; + + uint32_t px = (ext->dsc.header.w >> 3) * y + x; + buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += 4 * 4; + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + uint32_t px = (ext->dsc.header.w >> 2) * y + x; + + buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += 4 * 16; + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + uint32_t px = (ext->dsc.header.w >> 1) * y + x; + + buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += 4 * 256; + uint32_t px = ext->dsc.header.w * y + x; + buf_u8[px] = c.full; + } +} + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_CANVAS_STYLE_MAIN: + lv_img_set_style(canvas, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y) +{ + lv_color_t p_color = LV_COLOR_BLACK; + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_get_px: x or y out of the canvas"); + return p_color; + } + + uint8_t * buf_u8 = (uint8_t *) ext->dsc.data; + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR || + ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t); + memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += 4 * 2; + uint8_t bit = x & 0x7; + x = x >> 3; + + uint32_t px = (ext->dsc.header.w >> 3) * y + x; + p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += 4 * 4; + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + uint32_t px = (ext->dsc.header.w >> 2) * y + x; + p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += 4 * 16; + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + uint32_t px = (ext->dsc.header.w >> 1) * y + x; + p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += 4 * 256; + uint32_t px = ext->dsc.header.w * y + x; + p_color.full = buf_u8[px]; + } + return p_color; +} + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type) +{ + // lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + lv_style_t * style = NULL; + + switch(type) { + case LV_CANVAS_STYLE_MAIN: + style = lv_img_get_style(canvas); + break; + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_copy_buf: x or y out of the canvas"); + return; + } + + uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3; + uint32_t px = ext->dsc.header.w * y * px_size + x * px_size; + uint8_t * to_copy8 = (uint8_t *) to_copy; + lv_coord_t i; + for(i = 0; i < h; i++) { + memcpy((void*)&ext->dsc.data[px], to_copy8, w * px_size); + px += ext->dsc.header.w * px_size; + to_copy8 += w * px_size; + } +} + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_mult_buf: x or y out of the canvas"); + return; + } + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + LV_LOG_WARN("lv_canvas_mult_buf: LV_IMG_CF_TRUE_COLOR_ALPHA is not supported"); + return; + } + + uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3; + uint32_t px = ext->dsc.header.w * y * px_size + x * px_size; + lv_color_t * copy_buf_color = (lv_color_t *) to_copy; + lv_color_t * canvas_buf_color = (lv_color_t *) &ext->dsc.data[px]; + + lv_coord_t i; + lv_coord_t j; + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) { +#if LV_COLOR_DEPTH == 32 + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 8; + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 8; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 8; +#elif LV_COLOR_DEPTH == 16 + + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 5; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 5; +# if LV_COLOR_16_SWAP == 0 + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 6; +# else + uint8_t green_canvas = (canvas_buf_color[j].green_h << 3) + (canvas_buf_color[j].green_l); + uint8_t green_buf = (copy_buf_color[j].green_h << 3) + (copy_buf_color[j].green_l); + uint8_t green_res = (uint16_t)((uint16_t)green_canvas * green_buf) >> 6; + canvas_buf_color[j].green_h = (green_res >> 3) & 0x07; + canvas_buf_color[j].green_l = green_res & 0x07; +# endif /*LV_COLOR_16_SWAP*/ + +#elif LV_COLOR_DEPTH == 8 + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 3; + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 3; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 2; +#endif + } + copy_buf_color += w; + canvas_buf_color += ext->dsc.header.w; + } +} + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color) +{ + int x = radius; + int y = 0; + int err = 0; + + while (x >= y) + { + lv_canvas_set_px(canvas, x0 + x, y0 + y, color); + lv_canvas_set_px(canvas, x0 + y, y0 + x, color); + lv_canvas_set_px(canvas, x0 - y, y0 + x, color); + lv_canvas_set_px(canvas, x0 - x, y0 + y, color); + lv_canvas_set_px(canvas, x0 - x, y0 - y, color); + lv_canvas_set_px(canvas, x0 - y, y0 - x, color); + lv_canvas_set_px(canvas, x0 + y, y0 - x, color); + lv_canvas_set_px(canvas, x0 + x, y0 - y, color); + + if (err <= 0) + { + y += 1; + err += 2*y + 1; + } + + if (err > 0) + { + x -= 1; + err -= 2*x + 1; + } + } +} + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +/* + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color) +{ + lv_coord_t x0, y0, x1, y1; + + x0 = point1.x; + y0 = point1.y; + x1 = point2.x; + y1 = point2.y; + + int dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; + + for(;;){ + lv_canvas_set_px(canvas, x0, y0, color); + + if (x0==x1 && y0==y1) break; + e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color) +{ + lv_canvas_draw_polygon(canvas, points, 3, color); +} + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color) +{ + lv_canvas_draw_polygon(canvas, points, 4, color); +} + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color) +{ + uint8_t i; + + for(i=0; i < (size - 1); i++) { + lv_canvas_draw_line(canvas, points[i], points[i + 1], color); + } + + lv_canvas_draw_line(canvas, points[size - 1], points[0], color); +} + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color) +{ + uint32_t x = 0, y = 0; + uint8_t i; + + for(i=0; itype[i] == NULL) break; + } + buf->type[i] = "lv_canvas"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_canvas.h b/bdk/libs/lvgl/lv_objx/lv_canvas.h new file mode 100644 index 0000000..cd5827f --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_canvas.h @@ -0,0 +1,229 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CANVAS != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of canvas*/ +typedef struct { + lv_img_ext_t img; /*Ext. of ancestor*/ + /*New data for this type */ + lv_img_dsc_t dsc; +} lv_canvas_ext_t; + + +/*Styles*/ +enum { + LV_CANVAS_STYLE_MAIN, +}; +typedef uint8_t lv_canvas_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y); + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color); + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color); + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color); + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color); +/** + * Boundary fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param boundary_color edge/boundary color of the area + * @param fill_color fill color of the area + */ +void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color); + +/** + * Flood fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param fill_color fill color of the area + * @param bg_color background color of the area + */ +void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CANVAS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_cb.c b/bdk/libs/lvgl/lv_objx/lv_cb.c new file mode 100644 index 0000000..6b0277e --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_cb.c @@ -0,0 +1,347 @@ +/** + * @file lv_cb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cb.h" +#if USE_LV_CB != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_bg_design; +static lv_design_func_t ancestor_bullet_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + LV_LOG_TRACE("check box create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_cb = lv_btn_create(par, copy); + lv_mem_assert(new_cb); + if(new_cb == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cb); + if(ancestor_bg_design == NULL) ancestor_bg_design = lv_obj_get_design_func(new_cb); + + lv_cb_ext_t * ext = lv_obj_allocate_ext_attr(new_cb, sizeof(lv_cb_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->bullet = NULL; + ext->label = NULL; + + lv_obj_set_signal_func(new_cb, lv_cb_signal); + lv_obj_set_design_func(new_cb, lv_cb_design); + + /*Init the new checkbox object*/ + if(copy == NULL) { + ext->bullet = lv_btn_create(new_cb, NULL); + if(ancestor_bullet_design == NULL) ancestor_bullet_design = lv_obj_get_design_func(ext->bullet); + lv_obj_set_click(ext->bullet, false); + + ext->label = lv_label_create(new_cb, NULL); + + lv_cb_set_text(new_cb, "Check box"); + lv_btn_set_layout(new_cb, LV_LAYOUT_ROW_M); + lv_btn_set_fit(new_cb, true, true); + lv_btn_set_toggle(new_cb, true); + lv_obj_set_protect(new_cb, LV_PROTECT_PRESS_LOST); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_cb_set_style(new_cb, LV_CB_STYLE_BG, th->cb.bg); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, th->cb.box.rel); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_PR, th->cb.box.pr); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_REL, th->cb.box.tgl_rel); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_PR, th->cb.box.tgl_pr); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_INA, th->cb.box.ina); + } else { + lv_cb_set_style(new_cb, LV_CB_STYLE_BG, &lv_style_transp); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, &lv_style_pretty); + } + } else { + lv_cb_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->bullet = lv_btn_create(new_cb, copy_ext->bullet); + ext->label = lv_label_create(new_cb, copy_ext->label); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_cb); + } + + lv_obj_set_design_func(ext->bullet, lv_bullet_design); + + + LV_LOG_INFO("check box created"); + + return new_cb; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + lv_label_set_text(ext->label, txt); +} + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t * style) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + switch(type) { + case LV_CB_STYLE_BG: + lv_btn_set_style(cb, LV_BTN_STYLE_REL, style); + lv_btn_set_style(cb, LV_BTN_STYLE_PR, style); + lv_btn_set_style(cb, LV_BTN_STYLE_TGL_REL, style); + lv_btn_set_style(cb, LV_BTN_STYLE_TGL_PR, style); + lv_btn_set_style(cb, LV_BTN_STYLE_INA, style); + break; + case LV_CB_STYLE_BOX_REL: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_REL, style); + break; + case LV_CB_STYLE_BOX_PR: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_PR, style); + break; + case LV_CB_STYLE_BOX_TGL_REL: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_REL, style); + break; + case LV_CB_STYLE_BOX_TGL_PR: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_PR, style); + break; + case LV_CB_STYLE_BOX_INA: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_INA, style); + break; + } +} + + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + return lv_label_get_text(ext->label); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type) +{ + lv_style_t * style = NULL; + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + switch(type) { + case LV_CB_STYLE_BOX_REL: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_REL); + break; + case LV_CB_STYLE_BOX_PR: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_PR); + break; + case LV_CB_STYLE_BOX_TGL_REL: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_REL); + break; + case LV_CB_STYLE_BOX_TGL_PR: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_PR); + break; + case LV_CB_STYLE_BOX_INA: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the check boxes + * @param cb pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode) +{ + bool result = true; + + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + result = ancestor_bg_design(cb, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN || mode == LV_DESIGN_DRAW_POST) { + lv_cb_ext_t * cb_ext = lv_obj_get_ext_attr(cb); + lv_btn_ext_t * bullet_ext = lv_obj_get_ext_attr(cb_ext->bullet); + + /*Be sure the state of the bullet is the same as the parent button*/ + bullet_ext->state = cb_ext->bg_btn.state; + + result = ancestor_bg_design(cb, mask, mode); + + } else { + result = ancestor_bg_design(cb, mask, mode); + } + + return result; +} + +/** + * Handle the drawing related tasks of the check boxes + * @param bullet pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_bullet_design(bullet, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { +#if USE_LV_GROUP + /* If the check box is the active in a group and + * the background is not visible (transparent or empty) + * then activate the style of the bullet*/ + lv_style_t * style_ori = lv_obj_get_style(bullet); + lv_obj_t * bg = lv_obj_get_parent(bullet); + lv_style_t * style_page = lv_obj_get_style(bg); + lv_group_t * g = lv_obj_get_group(bg); + if(style_page->body.empty != 0 || style_page->body.opa == LV_OPA_TRANSP) { /*Background is visible?*/ + if(lv_group_get_focused(g) == bg) { + lv_style_t * style_mod; + style_mod = lv_group_mod_style(g, style_ori); + bullet->style_p = style_mod; /*Temporally change the style to the activated */ + } + } +#endif + ancestor_bullet_design(bullet, mask, mode); + +#if USE_LV_GROUP + bullet->style_p = style_ori; /*Revert the style*/ +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_bullet_design(bullet, mask, mode); + } + + return true; +} + + +/** + * Signal function of the check box + * @param cb pointer to a check box object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(cb, sign, param); + if(res != LV_RES_OK) return res; + + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + if(sign == LV_SIGNAL_STYLE_CHG) { + lv_style_t * label_style = lv_label_get_style(ext->label); + lv_obj_set_size(ext->bullet, lv_font_get_height(label_style->text.font), lv_font_get_height(label_style->text.font)); + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } else if(sign == LV_SIGNAL_PRESSED || + sign == LV_SIGNAL_RELEASED || + sign == LV_SIGNAL_PRESS_LOST) { + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN || + c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP || + c == LV_GROUP_KEY_ENTER) { + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_cb"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_cb.h b/bdk/libs/lvgl/lv_objx/lv_cb.h new file mode 100644 index 0000000..b587733 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_cb.h @@ -0,0 +1,174 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CB_H +#define LV_CB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of check box*/ +typedef struct +{ + lv_btn_ext_t bg_btn; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * bullet; /*Pointer to button*/ + lv_obj_t * label; /*Pointer to label*/ +} lv_cb_ext_t; + +enum { + LV_CB_STYLE_BG, + LV_CB_STYLE_BOX_REL, + LV_CB_STYLE_BOX_PR, + LV_CB_STYLE_BOX_TGL_REL, + LV_CB_STYLE_BOX_TGL_PR, + LV_CB_STYLE_BOX_INA, +}; +typedef uint8_t lv_cb_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt); + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +static inline void lv_cb_set_checked(lv_obj_t * cb, bool checked) +{ + lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_inactive(lv_obj_t * cb) +{ + lv_btn_set_state(cb, LV_BTN_STATE_INA); +} + +/** + * Set a function to call when the check box is clicked + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action) +{ + lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action); +} + + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb); + +/** + * Get the current state of the check box + * @param cb pointer to a check box object + * @return true: checked; false: not checked + */ +static inline bool lv_cb_is_checked(const lv_obj_t * cb) +{ + return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true; +} + +/** + * Get the action of a check box + * @param cb pointer to a button object + * @return pointer to the action function + */ +static inline lv_action_t lv_cb_get_action(const lv_obj_t * cb) +{ + return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CB_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_chart.c b/bdk/libs/lvgl/lv_objx/lv_chart.c new file mode 100644 index 0000000..0060c14 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_chart.c @@ -0,0 +1,824 @@ +/** + * @file lv_chart.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_chart.h" +#if USE_LV_CHART != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_YMIN_DEF 0 +#define LV_CHART_YMAX_DEF 100 +#define LV_CHART_HDIV_DEF 3 +#define LV_CHART_VDIV_DEF 5 +#define LV_CHART_PNUM_DEF 10 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param); +static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("chart create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_chart = lv_obj_create(par, copy); + lv_mem_assert(new_chart); + if(new_chart == NULL) return NULL; + + /*Allocate the object type specific extended data*/ + lv_chart_ext_t * ext = lv_obj_allocate_ext_attr(new_chart, sizeof(lv_chart_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t)); + ext->series.num = 0; + ext->ymin = LV_CHART_YMIN_DEF; + ext->ymax = LV_CHART_YMAX_DEF; + ext->hdiv_cnt = LV_CHART_HDIV_DEF; + ext->vdiv_cnt = LV_CHART_VDIV_DEF; + ext->point_cnt = LV_CHART_PNUM_DEF; + ext->type = LV_CHART_TYPE_LINE; + ext->series.opa = LV_OPA_COVER; + ext->series.dark = LV_OPA_50; + ext->series.width = 2; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_chart); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_chart); + + lv_obj_set_signal_func(new_chart, lv_chart_signal); + lv_obj_set_design_func(new_chart, lv_chart_design); + + /*Init the new chart background object*/ + if(copy == NULL) { + lv_obj_set_size(new_chart, LV_HOR_RES / 3, LV_VER_RES / 3); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_chart_set_style(new_chart, th->chart); + } else { + lv_chart_set_style(new_chart, &lv_style_pretty); + } + + } else { + lv_chart_ext_t * ext_copy = lv_obj_get_ext_attr(copy); + ext->type = ext_copy->type; + ext->ymin = ext_copy->ymin; + ext->ymax = ext_copy->ymax; + ext->hdiv_cnt = ext_copy->hdiv_cnt; + ext->vdiv_cnt = ext_copy->vdiv_cnt; + ext->point_cnt = ext_copy->point_cnt; + ext->series.opa = ext_copy->series.opa; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_chart); + } + + LV_LOG_INFO("chart created"); + + + return new_chart; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_chart_series_t * ser = lv_ll_ins_head(&ext->series_ll); + lv_mem_assert(ser); + if(ser == NULL) return NULL; + + lv_coord_t def = LV_CHART_POINT_DEF; + + if(ser == NULL) return NULL; + + ser->color = color; + + ser->points = lv_mem_alloc(sizeof(lv_coord_t) * ext->point_cnt); + lv_mem_assert(ser->points); + if(ser->points == NULL) { + lv_ll_rem(&ext->series_ll, ser); + lv_mem_free(ser); + return NULL; + } + + ser->start_point = 0; + + uint16_t i; + lv_coord_t * p_tmp = ser->points; + for(i = 0; i < ext->point_cnt; i++) { + *p_tmp = def; + p_tmp++; + } + + ext->series.num++; + + return ser; +} + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie) +{ + if(chart == NULL || serie == NULL) + return; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext == NULL) return; + + uint32_t i; + for(i = 0; i < ext->point_cnt; i++) + { + serie->points[i] = LV_CHART_POINT_DEF; + } + + serie->start_point = 0; + +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->hdiv_cnt == hdiv && ext->vdiv_cnt == vdiv) return; + + ext->hdiv_cnt = hdiv; + ext->vdiv_cnt = vdiv; + + lv_obj_invalidate(chart); +} + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->ymin == ymin && ext->ymax == ymax) return; + + ext->ymin = ymin; + ext->ymax = ymax; + + lv_chart_refresh(chart); +} + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->type == type) return; + + ext->type = type; + + lv_chart_refresh(chart); +} + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->point_cnt == point_cnt) return; + + lv_chart_series_t * ser; + uint16_t point_cnt_old = ext->point_cnt; + uint16_t i; + lv_coord_t def = LV_CHART_POINT_DEF; + + if(point_cnt < 1) point_cnt = 1; + + LL_READ_BACK(ext->series_ll, ser) { + if(ser->start_point != 0) { + lv_coord_t * new_points = lv_mem_alloc(sizeof(lv_coord_t) * point_cnt); + lv_mem_assert(new_points); + if(new_points == NULL) return; + + if(point_cnt >= point_cnt_old) { + for(i = 0; i < point_cnt_old; i++) { + new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old]; /*Copy old contents to new array*/ + } + for(i = point_cnt_old; i < point_cnt; i++) { + new_points[i] = def; /*Fill up the rest with default value*/ + } + } else { + for(i = 0; i < point_cnt; i++) { + new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old]; /*Copy old contents to new array*/ + } + } + + /*Switch over pointer from old to new*/ + lv_mem_free(ser->points); + ser->points = new_points; + } else { + ser->points = lv_mem_realloc(ser->points, sizeof(lv_coord_t) * point_cnt); + lv_mem_assert(ser->points); + if(ser->points == NULL) return; + /*Initialize the new points*/ + if(point_cnt > point_cnt_old) { + for(i = point_cnt_old - 1; i < point_cnt; i++) { + ser->points[i] = def; + } + } + } + + ser->start_point = 0; + } + + ext->point_cnt = point_cnt; + + lv_chart_refresh(chart); +} + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.opa == opa) return; + + ext->series.opa = opa; + lv_obj_invalidate(chart); +} + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.width == width) return; + + ext->series.width = width; + lv_obj_invalidate(chart); +} +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.dark == dark_eff) return; + + ext->series.dark = dark_eff; + lv_obj_invalidate(chart); +} + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + uint16_t i; + for(i = 0; i < ext->point_cnt; i++) { + ser->points[i] = y; + } + ser->start_point = 0; + lv_chart_refresh(chart); +} + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + memcpy(ser->points, y_array, ext->point_cnt * (sizeof(lv_coord_t))); + ser->start_point = 0; + lv_chart_refresh(chart); +} + +/** + * Shift all data left and set the rightmost data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the rightmost data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + ser->points[ser->start_point] = y; /*This was the place of the former left most value, after shifting it is the rightmost*/ + ser->start_point = (ser->start_point + 1) % ext->point_cnt; + + lv_chart_refresh(chart); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->type; +} + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->point_cnt; +} + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.opa; +} + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.width; +} + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.dark; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart) +{ + lv_obj_invalidate(chart); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the chart backgrounds + * @param chart pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return ancestor_design_f(chart, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the background*/ + lv_draw_rect(&chart->coords, mask, lv_obj_get_style(chart), lv_obj_get_opa_scale(chart)); + + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + lv_chart_draw_div(chart, mask); + + if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask); + if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask); + if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask); + if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask); + } + return true; +} + +/** + * Signal function of the chart background + * @param chart pointer to a chart background object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + */ +static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(chart, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + lv_coord_t ** datal; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + LL_READ(ext->series_ll, datal) { + lv_mem_free(*datal); + } + lv_ll_clear(&ext->series_ll); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_chart"; + } + + return res; +} + +/** + * Draw the division lines on chart background + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_style_t * style = lv_obj_get_style(chart); + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + + uint8_t div_i; + uint8_t div_i_end; + uint8_t div_i_start; + lv_point_t p1; + lv_point_t p2; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + + if(ext->hdiv_cnt != 0) { + /*Draw slide lines if no border*/ + if(style->body.border.width != 0) { + div_i_start = 1; + div_i_end = ext->hdiv_cnt; + } else { + div_i_start = 0; + div_i_end = ext->hdiv_cnt + 1; + } + + p1.x = 0 + x_ofs; + p2.x = w + x_ofs; + for(div_i = div_i_start; div_i <= div_i_end; div_i++) { + p1.y = (int32_t)((int32_t)h * div_i) / (ext->hdiv_cnt + 1); + p1.y += y_ofs; + if(div_i == div_i_start) p1.y += (style->line.width >> 1) + 1; /*The first line might not be visible*/ + if(div_i == div_i_end) p1.y -= (style->line.width >> 1) + 1; /*The last line might not be visible*/ + + p2.y = p1.y; + lv_draw_line(&p1, &p2, mask, style, opa_scale); + } + } + + if(ext->vdiv_cnt != 0) { + /*Draw slide lines if no border*/ + if(style->body.border.width != 0) { + div_i_start = 1; + div_i_end = ext->vdiv_cnt; + } else { + div_i_start = 0; + div_i_end = ext->vdiv_cnt + 1; + } + + p1.y = 0 + y_ofs; + p2.y = h + y_ofs; + for(div_i = div_i_start; div_i <= div_i_end; div_i ++) { + p1.x = (int32_t)((int32_t)w * div_i) / (ext->vdiv_cnt + 1); + p1.x += x_ofs; + if(div_i == div_i_start) p1.x += (style->line.width >> 1) + 1; /*The first line might not be visible*/ + if(div_i == div_i_end) p1.x -= (style->line.width >> 1) + 1; /*The last line might not be visible*/ + p2.x = p1.x; + lv_draw_line(&p1, &p2, mask, style, opa_scale); + } + } +} + +/** + * Draw the data lines as lines on a chart + * @param obj pointer to chart object + */ +static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_point_t p1; + lv_point_t p2; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_coord_t p_prev; + lv_coord_t p_act; + lv_chart_series_t * ser; + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + lv_style_t style; + lv_style_copy(&style, &lv_style_plain); + style.line.opa = ext->series.opa; + style.line.width = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style.line.color = ser->color; + + p1.x = 0 + x_ofs; + p2.x = 0 + x_ofs; + + p_prev = ser->start_point; + y_tmp = (int32_t)((int32_t) ser->points[p_prev] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + for(i = 1; i < ext->point_cnt; i ++) { + p1.x = p2.x; + p1.y = p2.y; + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + + p_act = (ser->start_point + i) % ext->point_cnt; + + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(ser->points[p_prev] != LV_CHART_POINT_DEF && ser->points[p_act] != LV_CHART_POINT_DEF) + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + + p_prev = p_act; + } + } +} + +/** + * Draw the data lines as points on a chart + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_area_t cir_a; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_coord_t p_act; + lv_chart_series_t * ser; + uint8_t series_cnt = 0; + lv_style_t style_point; + lv_style_copy(&style_point, &lv_style_plain); + + style_point.body.border.width = 0; + style_point.body.empty = 0; + style_point.body.radius = LV_RADIUS_CIRCLE; + style_point.body.opa = ext->series.opa; + style_point.body.radius = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style_point.body.main_color = ser->color; + style_point.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark); + + for(i = 0; i < ext->point_cnt; i ++) { + cir_a.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + cir_a.x2 = cir_a.x1 + style_point.body.radius; + cir_a.x1 -= style_point.body.radius; + p_act = (ser->start_point + i) % ext->point_cnt; + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + cir_a.y1 = h - y_tmp + y_ofs; + cir_a.y2 = cir_a.y1 + style_point.body.radius; + cir_a.y1 -= style_point.body.radius; + + if(ser->points[p_act] != LV_CHART_POINT_DEF) + lv_draw_rect(&cir_a, mask, &style_point, lv_obj_get_opa_scale(chart)); + } + series_cnt++; + } +} + +/** + * Draw the data lines as columns on a chart + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_area_t col_a; + lv_area_t col_mask; + bool mask_ret; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + int32_t y_tmp; + lv_chart_series_t * ser; + lv_style_t rects; + lv_coord_t col_w = w / ((ext->series.num + 1) * ext->point_cnt); /* Suppose + 1 series as separator*/ + lv_coord_t x_ofs = col_w / 2; /*Shift with a half col.*/ + + lv_style_copy(&rects, &lv_style_plain); + rects.body.border.width = 0; + rects.body.empty = 0; + rects.body.radius = 0; + rects.body.opa = ext->series.opa; + + col_a.y2 = chart->coords.y2; + + lv_coord_t x_act; + + /*Go through all points*/ + for(i = 0; i < ext->point_cnt; i ++) { + x_act = (int32_t)((int32_t) w * i) / ext->point_cnt; + x_act += chart->coords.x1 + x_ofs; + + /*Draw the current point of all data line*/ + LL_READ_BACK(ext->series_ll, ser) { + rects.body.main_color = ser->color; + rects.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark); + col_a.x1 = x_act; + col_a.x2 = col_a.x1 + col_w; + x_act += col_w; + + lv_coord_t p_act = (ser->start_point + i) % ext->point_cnt; + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + col_a.y1 = h - y_tmp + chart->coords.y1; + + mask_ret = lv_area_intersect(&col_mask, mask, &col_a); + if(mask_ret != false && ser->points[p_act] != LV_CHART_POINT_DEF) { + lv_draw_rect(&chart->coords, &col_mask, &rects, lv_obj_get_opa_scale(chart)); + } + } + } +} + +/** + * Draw the data lines as vertical lines on a chart if there is only 1px between point + * @param obj pointer to chart object + */ +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask) +{ + + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_coord_t w = lv_obj_get_width(chart); + /*Vertical lines works only if the width == point count. Else use the normal line type*/ + if(ext->point_cnt != w) { + lv_chart_draw_lines(chart, mask); + return; + } + + uint16_t i; + lv_point_t p1; + lv_point_t p2; + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_chart_series_t * ser; + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + lv_style_t style; + lv_style_copy(&style, &lv_style_plain); + style.line.opa = ext->series.opa; + style.line.width = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style.line.color = ser->color; + + p1.x = 0 + x_ofs; + p2.x = 0 + x_ofs; + y_tmp = (int32_t)((int32_t) ser->points[0] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + p1.y = p2.y; + + for(i = 0; i < ext->point_cnt; i++) + { + + y_tmp = (int32_t)((int32_t) ser->points[i] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(p1.y == p2.y) + { + p2.x++; + } + + if(ser->points[i] != LV_CHART_POINT_DEF) { + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + } + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + p1.x = p2.x; + p1.y = p2.y; + } + } +} +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_chart.h b/bdk/libs/lvgl/lv_objx/lv_chart.h new file mode 100644 index 0000000..baea9d0 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_chart.h @@ -0,0 +1,262 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CHART != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_POINT_DEF (LV_COORD_MIN) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + lv_coord_t * points; + lv_color_t color; + uint16_t start_point; +} lv_chart_series_t; + +/*Data of chart */ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_dl_t)*/ + lv_coord_t ymin; /*y min value (used to scale the data)*/ + lv_coord_t ymax; /*y max value (used to scale the data)*/ + uint8_t hdiv_cnt; /*Number of horizontal division lines*/ + uint8_t vdiv_cnt; /*Number of vertical division lines*/ + uint16_t point_cnt; /*Point number in a data line*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ + struct { + lv_coord_t width; /*Line width or point radius*/ + uint8_t num; /*Number of data lines in dl_ll*/ + lv_opa_t opa; /*Opacity of data lines*/ + lv_opa_t dark; /*Dark level of the point/column bottoms*/ + } series; +} lv_chart_ext_t; + +/*Chart types*/ +enum +{ + LV_CHART_TYPE_LINE = 0x01, /*Connect the points with lines*/ + LV_CHART_TYPE_COLUMN = 0x02, /*Draw columns*/ + LV_CHART_TYPE_POINT = 0x04, /*Draw circles on the points*/ + LV_CHART_TYPE_VERTICAL_LINE = 0x08, /*Draw vertical lines on points (useful when chart width == point count)*/ +}; +typedef uint8_t lv_chart_type_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv); + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type); + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt); + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa); + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width); + +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff); + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array); + +/** + * Shift all data right and set the most right data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the most right data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the style of a chart + * @param chart pointer to a chart object + * @param style pointer to a style + */ +static inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style) +{ + lv_obj_set_style(chart, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart); + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart); + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart); + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart); + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart); + +/** + * Get the style of an chart object + * @param chart pointer to an chart object + * @return pointer to the chart's style + */ +static inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart) +{ + return lv_obj_get_style(chart); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CHART*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CHART_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_cont.c b/bdk/libs/lvgl/lv_objx/lv_cont.c new file mode 100644 index 0000000..bd84cd9 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_cont.c @@ -0,0 +1,642 @@ +/** + * @file lv_cont.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_cont.h" +#if USE_LV_CONT != 0 + +#include +#include + +#include "../lv_draw/lv_draw.h" +#include "../lv_draw/lv_draw_vbasic.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param); +static void lv_cont_refr_layout(lv_obj_t * cont); +static void lv_cont_layout_col(lv_obj_t * cont); +static void lv_cont_layout_row(lv_obj_t * cont); +static void lv_cont_layout_center(lv_obj_t * cont); +static void lv_cont_layout_pretty(lv_obj_t * cont); +static void lv_cont_layout_grid(lv_obj_t * cont); +static void lv_cont_refr_autofit(lv_obj_t * cont); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + + LV_LOG_TRACE("container create started"); + + /*Create a basic object*/ + lv_obj_t * new_cont = lv_obj_create(par, copy); + lv_mem_assert(new_cont); + if(new_cont == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cont); + + lv_obj_allocate_ext_attr(new_cont, sizeof(lv_cont_ext_t)); + lv_cont_ext_t * ext = lv_obj_get_ext_attr(new_cont); + if(ext == NULL) return NULL; + + lv_mem_assert(ext); + ext->hor_fit = 0; + ext->ver_fit = 0; + ext->layout = LV_LAYOUT_OFF; + + lv_obj_set_signal_func(new_cont, lv_cont_signal); + + /*Init the new container*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_cont_set_style(new_cont, th->cont); + } else { + lv_cont_set_style(new_cont, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_cont_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->hor_fit = copy_ext->hor_fit; + ext->ver_fit = copy_ext->ver_fit; + ext->layout = copy_ext->layout; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_cont); + } + + LV_LOG_INFO("container created"); + + + return new_cont; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + if(ext->layout == layout) return; + + ext->layout = layout; + + /*Send a signal to refresh the layout*/ + cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL); +} + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en) +{ + lv_obj_invalidate(cont); + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + if(ext->hor_fit == hor_en && ext->ver_fit == ver_en) return; + + ext->hor_fit = hor_en == false ? 0 : 1; + ext->ver_fit = ver_en == false ? 0 : 1; + + /*Send a signal to refresh the layout*/ + cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->layout; +} + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->hor_fit == 0 ? false : true; +} + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->ver_fit == 0 ? false : true; +} + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont) +{ + lv_style_t * style = lv_cont_get_style(cont); + + return lv_obj_get_width(cont) - 2 * style->body.padding.hor; +} + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont) +{ + lv_style_t * style = lv_cont_get_style(cont); + + return lv_obj_get_height(cont) - 2 * style->body.padding.ver; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the container + * @param cont pointer to a container object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(cont, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_STYLE_CHG) { /*Recalculate the padding if the style changed*/ + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } else if(sign == LV_SIGNAL_CHILD_CHG) { + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_obj_get_width(cont) != lv_area_get_width(param) || + lv_obj_get_height(cont) != lv_area_get_height(param)) { + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_cont"; + } + + return res; +} + + +/** + * Refresh the layout of a container + * @param cont pointer to an object which layout should be refreshed + */ +static void lv_cont_refr_layout(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + + /*'cont' has to be at least 1 child*/ + if(lv_obj_get_child(cont, NULL) == NULL) return; + + if(type == LV_LAYOUT_OFF) return; + + if(type == LV_LAYOUT_CENTER) { + lv_cont_layout_center(cont); + } else if(type == LV_LAYOUT_COL_L || type == LV_LAYOUT_COL_M || type == LV_LAYOUT_COL_R) { + lv_cont_layout_col(cont); + } else if(type == LV_LAYOUT_ROW_T || type == LV_LAYOUT_ROW_M || type == LV_LAYOUT_ROW_B) { + lv_cont_layout_row(cont); + } else if(type == LV_LAYOUT_PRETTY) { + lv_cont_layout_pretty(cont); + } else if(type == LV_LAYOUT_GRID) { + lv_cont_layout_grid(cont); + } +} + +/** + * Handle column type layouts + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_col(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + lv_obj_t * child; + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t hpad_corr; + + switch(type) { + case LV_LAYOUT_COL_L: + hpad_corr = style->body.padding.hor; + align = LV_ALIGN_IN_TOP_LEFT; + break; + case LV_LAYOUT_COL_M: + hpad_corr = 0; + align = LV_ALIGN_IN_TOP_MID; + break; + case LV_LAYOUT_COL_R: + hpad_corr = -style->body.padding.hor; + align = LV_ALIGN_IN_TOP_RIGHT; + break; + default: + hpad_corr = 0; + align = LV_ALIGN_IN_TOP_LEFT; + break; + } + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + /* Align the children */ + lv_coord_t last_cord = style->body.padding.ver; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, align, hpad_corr, last_cord); + last_cord += lv_obj_get_height(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle row type layouts + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_row(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + lv_obj_t * child; + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t vpad_corr = style->body.padding.ver; + + switch(type) { + case LV_LAYOUT_ROW_T: + vpad_corr = style->body.padding.ver; + align = LV_ALIGN_IN_TOP_LEFT; + break; + case LV_LAYOUT_ROW_M: + vpad_corr = 0; + align = LV_ALIGN_IN_LEFT_MID; + break; + case LV_LAYOUT_ROW_B: + vpad_corr = -style->body.padding.ver; + align = LV_ALIGN_IN_BOTTOM_LEFT; + break; + default: + vpad_corr = 0; + align = LV_ALIGN_IN_TOP_LEFT; + break; + } + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t last_cord = style->body.padding.hor; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, align, last_cord, vpad_corr); + last_cord += lv_obj_get_width(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the center layout + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_center(lv_obj_t * cont) +{ + lv_obj_t * child; + lv_style_t * style = lv_obj_get_style(cont); + uint32_t obj_num = 0; + lv_coord_t h_tot = 0; + + LL_READ(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + h_tot += lv_obj_get_height(child) + style->body.padding.inner; + obj_num ++; + } + + if(obj_num == 0) return; + + h_tot -= style->body.padding.inner; + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t last_cord = - (h_tot / 2); + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, LV_ALIGN_CENTER, 0, last_cord + lv_obj_get_height(child) / 2); + last_cord += lv_obj_get_height(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the pretty layout. Put as many object as possible in row + * then begin a new row + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_pretty(lv_obj_t * cont) +{ + lv_obj_t * child_rs; /* Row starter child */ + lv_obj_t * child_rc; /* Row closer child */ + lv_obj_t * child_tmp; /* Temporary child */ + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t w_obj = lv_obj_get_width(cont); + lv_coord_t act_y = style->body.padding.ver; + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + + child_rs = lv_ll_get_tail(&cont->child_ll); /*Set the row starter child*/ + if(child_rs == NULL) return; /*Return if no child*/ + + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + child_rc = child_rs; /*Initially the the row starter and closer is the same*/ + while(child_rs != NULL) { + lv_coord_t h_row = 0; + lv_coord_t w_row = style->body.padding.hor * 2; /*The width is at least the left+right hpad*/ + uint32_t obj_num = 0; + + /*Find the row closer object and collect some data*/ + do { + if(lv_obj_get_hidden(child_rc) == false && + lv_obj_is_protected(child_rc, LV_PROTECT_POS) == false) { + /*If this object is already not fit then break*/ + if(w_row + lv_obj_get_width(child_rc) > w_obj) { + /*Step back one child because the last already not fit, so the previous is the closer*/ + if(child_rc != NULL && obj_num != 0) { + child_rc = lv_ll_get_next(&cont->child_ll, child_rc); + } + break; + } + w_row += lv_obj_get_width(child_rc) + style->body.padding.inner; /*Add the object width + opad*/ + h_row = LV_MATH_MAX(h_row, lv_obj_get_height(child_rc)); /*Search the highest object*/ + obj_num ++; + if(lv_obj_is_protected(child_rc, LV_PROTECT_FOLLOW)) break; /*If can not be followed by an other object then break here*/ + + } + child_rc = lv_ll_get_prev(&cont->child_ll, child_rc); /*Load the next object*/ + if(obj_num == 0) child_rs = child_rc; /*If the first object was hidden (or too long) then set the next as first */ + } while(child_rc != NULL); + + /*If the object is too long then align it to the middle*/ + if(obj_num == 0) { + if(child_rc != NULL) { + lv_obj_align(child_rc, cont, LV_ALIGN_IN_TOP_MID, 0, act_y); + h_row = lv_obj_get_height(child_rc); /*Not set previously because of the early break*/ + } + } + /*If there is only one object in the row then align it to the middle*/ + else if(obj_num == 1) { + lv_obj_align(child_rs, cont, LV_ALIGN_IN_TOP_MID, 0, act_y); + } + /*If there are two object in the row then align them proportionally*/ + else if(obj_num == 2) { + lv_obj_t * obj1 = child_rs; + lv_obj_t * obj2 = lv_ll_get_prev(&cont->child_ll, child_rs); + w_row = lv_obj_get_width(obj1) + lv_obj_get_width(obj2); + lv_coord_t pad = (w_obj - w_row) / 3; + lv_obj_align(obj1, cont, LV_ALIGN_IN_TOP_LEFT, pad, act_y + (h_row - lv_obj_get_height(obj1)) / 2); + lv_obj_align(obj2, cont, LV_ALIGN_IN_TOP_RIGHT, -pad, act_y + (h_row - lv_obj_get_height(obj2)) / 2); + } + /* Align the children (from child_rs to child_rc)*/ + else { + w_row -= style->body.padding.inner * obj_num; + lv_coord_t new_opad = (w_obj - w_row) / (obj_num - 1); + lv_coord_t act_x = style->body.padding.hor; /*x init*/ + child_tmp = child_rs; + while(child_tmp != NULL) { + if(lv_obj_get_hidden(child_tmp) == false && + lv_obj_is_protected(child_tmp, LV_PROTECT_POS) == false) { + lv_obj_align(child_tmp, cont, LV_ALIGN_IN_TOP_LEFT, act_x, act_y + (h_row - lv_obj_get_height(child_tmp)) / 2); + act_x += lv_obj_get_width(child_tmp) + new_opad; + } + if(child_tmp == child_rc) break; + child_tmp = lv_ll_get_prev(&cont->child_ll, child_tmp); + } + + } + + if(child_rc == NULL) break; + act_y += style->body.padding.inner + h_row; /*y increment*/ + child_rs = lv_ll_get_prev(&cont->child_ll, child_rc); /*Go to the next object*/ + child_rc = child_rs; + } + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the grid layout. Align same-sized objects in a grid + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_grid(lv_obj_t * cont) +{ + lv_obj_t * child; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t w_tot = lv_obj_get_width(cont); + lv_coord_t w_obj = lv_obj_get_width(lv_obj_get_child(cont, NULL)); + lv_coord_t h_obj = lv_obj_get_height(lv_obj_get_child(cont, NULL)); + uint16_t obj_row = (w_tot - (2 * style->body.padding.hor)) / (w_obj + style->body.padding.inner); /*Obj. num. in a row*/ + lv_coord_t x_ofs; + if(obj_row > 1) { + x_ofs = w_obj + (w_tot - (2 * style->body.padding.hor) - (obj_row * w_obj)) / (obj_row - 1); + } else { + x_ofs = w_tot / 2 - w_obj / 2; + } + lv_coord_t y_ofs = h_obj + style->body.padding.inner; + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t act_x = style->body.padding.hor; + lv_coord_t act_y = style->body.padding.ver; + uint16_t obj_cnt = 0; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + if(obj_row > 1) { + lv_obj_set_pos(child, act_x, act_y); + act_x += x_ofs; + } else { + lv_obj_set_pos(child, x_ofs, act_y); + } + obj_cnt ++; + + if(obj_cnt >= obj_row) { + obj_cnt = 0; + act_x = style->body.padding.hor; + act_y += y_ofs; + } + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle auto fit. Set the size of the object to involve all children. + * @param cont pointer to an object which size will be modified + */ +static void lv_cont_refr_autofit(lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + + if(ext->hor_fit == 0 && + ext->ver_fit == 0) { + return; + } + + lv_area_t new_cords; + lv_area_t ori; + lv_style_t * style = lv_obj_get_style(cont); + lv_obj_t * i; + lv_coord_t hpad = style->body.padding.hor; + lv_coord_t vpad = style->body.padding.ver; + + /*Search the side coordinates of the children*/ + lv_obj_get_coords(cont, &ori); + lv_obj_get_coords(cont, &new_cords); + + new_cords.x1 = LV_COORD_MAX; + new_cords.y1 = LV_COORD_MAX; + new_cords.x2 = LV_COORD_MIN; + new_cords.y2 = LV_COORD_MIN; + + LL_READ(cont->child_ll, i) { + if(lv_obj_get_hidden(i) != false) continue; + new_cords.x1 = LV_MATH_MIN(new_cords.x1, i->coords.x1); + new_cords.y1 = LV_MATH_MIN(new_cords.y1, i->coords.y1); + new_cords.x2 = LV_MATH_MAX(new_cords.x2, i->coords.x2); + new_cords.y2 = LV_MATH_MAX(new_cords.y2, i->coords.y2); + } + + /*If the value is not the init value then the page has >=1 child.*/ + if(new_cords.x1 != LV_COORD_MAX) { + if(ext->hor_fit != 0) { + new_cords.x1 -= hpad; + new_cords.x2 += hpad; + } else { + new_cords.x1 = cont->coords.x1; + new_cords.x2 = cont->coords.x2; + } + if(ext->ver_fit != 0) { + new_cords.y1 -= vpad; + new_cords.y2 += vpad; + } else { + new_cords.y1 = cont->coords.y1; + new_cords.y2 = cont->coords.y2; + } + + /*Do nothing if the coordinates are not changed*/ + if(cont->coords.x1 != new_cords.x1 || + cont->coords.y1 != new_cords.y1 || + cont->coords.x2 != new_cords.x2 || + cont->coords.y2 != new_cords.y2) { + + lv_obj_invalidate(cont); + lv_area_copy(&cont->coords, &new_cords); + lv_obj_invalidate(cont); + + /*Notify the object about its new coordinates*/ + cont->signal_func(cont, LV_SIGNAL_CORD_CHG, &ori); + + /*Inform the parent about the new coordinates*/ + lv_obj_t * par = lv_obj_get_parent(cont); + par->signal_func(par, LV_SIGNAL_CHILD_CHG, cont); + } + } +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_cont.h b/bdk/libs/lvgl/lv_objx/lv_cont.h new file mode 100644 index 0000000..3259c77 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_cont.h @@ -0,0 +1,163 @@ +/** + * @file lv_cont.h + * + */ + +#ifndef LV_CONT_H +#define LV_CONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CONT != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Layout options*/ +enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_CENTER, + LV_LAYOUT_COL_L, /*Column left align*/ + LV_LAYOUT_COL_M, /*Column middle align*/ + LV_LAYOUT_COL_R, /*Column right align*/ + LV_LAYOUT_ROW_T, /*Row top align*/ + LV_LAYOUT_ROW_M, /*Row middle align*/ + LV_LAYOUT_ROW_B, /*Row bottom align*/ + LV_LAYOUT_PRETTY, /*Put as many object as possible in row and begin a new row*/ + LV_LAYOUT_GRID, /*Align same-sized object into a grid*/ +}; +typedef uint8_t lv_layout_t; + +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ + /*New data for this type */ + uint8_t layout :4; /*A layout from 'lv_cont_layout_t' enum*/ + uint8_t hor_fit :1; /*1: Enable horizontal fit to involve all children*/ + uint8_t ver_fit :1; /*1: Enable horizontal fit to involve all children*/ +} lv_cont_ext_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en); + +/** + * Set the style of a container + * @param cont pointer to a container object + * @param style pointer to the new style + */ +static inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style) +{ + lv_obj_set_style(cont, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont); + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont); + + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont); + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont); + +/** + * Get the style of a container + * @param cont pointer to a container object + * @return pointer to the container's style + */ +static inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont) +{ + return lv_obj_get_style(cont); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CONT*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CONT_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_ddlist.c b/bdk/libs/lvgl/lv_objx/lv_ddlist.c new file mode 100644 index 0000000..c3776e8 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_ddlist.c @@ -0,0 +1,981 @@ +/* + * 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 . + */ + +/** + * @file lv_ddlist.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_ddlist.h" +#if USE_LV_DDLIST != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_indev.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_symbol_def.h" +#include "../lv_misc/lv_anim.h" +//#include + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 200 /*ms*/ +# endif +#else +# undef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 0 /*No animation*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param); +static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist); +static lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist); +static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en); +static void lv_ddlist_pos_current_option(lv_obj_t * ddlist); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("drop down list create started"); + + /*Create the ancestor drop down list*/ + lv_obj_t * new_ddlist = lv_page_create(par, copy); + lv_mem_assert(new_ddlist); + if(new_ddlist == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ddlist); + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ddlist)); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ddlist); + + /*Allocate the drop down list type specific extended data*/ + lv_ddlist_ext_t * ext = lv_obj_allocate_ext_attr(new_ddlist, sizeof(lv_ddlist_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->label = NULL; + ext->action = NULL; + ext->opened = 0; + ext->fix_height = 0; + ext->sel_opt_id = 0; + ext->sel_opt_id_ori = 0; + ext->option_cnt = 0; + ext->anim_time = LV_DDLIST_ANIM_TIME; + ext->sel_style = &lv_style_plain_color; + ext->draw_arrow = 0; /*Do not draw arrow by default*/ + ext->direction_up = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_ddlist, lv_ddlist_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_ddlist), lv_ddlist_scrl_signal); + lv_obj_set_design_func(new_ddlist, lv_ddlist_design); + + /*Init the new drop down list drop down list*/ + if(copy == NULL) { + lv_obj_t * scrl = lv_page_get_scrl(new_ddlist); + lv_obj_set_drag(scrl, false); + lv_page_set_scrl_fit(new_ddlist, true, true); + + ext->label = lv_label_create(new_ddlist, NULL); + lv_cont_set_fit(new_ddlist, true, false); + lv_page_set_rel_action(new_ddlist, lv_ddlist_release_action); + lv_page_set_pr_action(new_ddlist, lv_ddlist_press_action); + lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_DRAG); + lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE); + lv_page_set_style(new_ddlist, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + + lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3"); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, th->ddlist.bg); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, th->ddlist.bgo); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, th->ddlist.pr); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, th->ddlist.sel); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, th->ddlist.sb); + } else { + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color); + } + } + /*Copy an existing drop down list*/ + else { + lv_ddlist_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->label = lv_label_create(new_ddlist, copy_ext->label); + lv_label_set_text(ext->label, lv_label_get_text(copy_ext->label)); + ext->sel_opt_id = copy_ext->sel_opt_id; + ext->fix_height = copy_ext->fix_height; + ext->action = copy_ext->action; + ext->option_cnt = copy_ext->option_cnt; + ext->sel_style = copy_ext->sel_style; + ext->anim_time = copy_ext->anim_time; + ext->draw_arrow = copy_ext->draw_arrow; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_ddlist); + } + + LV_LOG_INFO("drop down list created"); + + + return new_ddlist; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*Set the flag*/ + ext->draw_arrow = en; +} + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*Count the '\n'-s to determine the number of options*/ + ext->option_cnt = 0; + uint16_t i; + for(i = 0; options[i] != '\0'; i++) { + if(options[i] == '\n') ext->option_cnt++; + } + ext->option_cnt++; /*Last option in the at row*/ + + lv_label_set_text(ext->label, options); + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + if(ext->sel_opt_id == sel_opt) return; + + ext->sel_opt_id = sel_opt < ext->option_cnt ? sel_opt : ext->option_cnt - 1; + ext->sel_opt_id_ori = ext->sel_opt_id; + /*Move the list to show the current option*/ + if(ext->opened == 0) { + lv_ddlist_pos_current_option(ddlist); + } else { + lv_obj_invalidate(ddlist); + } +} + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->action = action; +} + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + if(ext->fix_height == h) return; + + ext->fix_height = h; + + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en) +{ + lv_cont_set_fit(ddlist, en, lv_cont_get_ver_fit(ddlist)); + lv_page_set_scrl_fit(ddlist, en, lv_page_get_scrl_fit_ver(ddlist)); + + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + ext->anim_time = anim_time; +} + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ddlist_set_style(lv_obj_t * ddlist, lv_ddlist_style_t type, lv_style_t * style) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + switch(type) { + case LV_DDLIST_STYLE_BG: + lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style); + break; + case LV_DDLIST_STYLE_BGO: + lv_page_set_style(ddlist, LV_PAGE_STYLE_BGO, style); + break; + case LV_DDLIST_STYLE_PR: + lv_page_set_style(ddlist, LV_PAGE_STYLE_PR, style); + break; + case LV_DDLIST_STYLE_SB: + lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style); + break; + case LV_DDLIST_STYLE_SEL: + ext->sel_style = style; + lv_obj_t * scrl = lv_page_get_scrl(ddlist); + lv_obj_refresh_ext_size(scrl); /*Because of the wider selected rectangle*/ + break; + } +} + +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + lv_label_set_align(ext->label, align); +} + +void lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + ext->direction_up = enable; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return ext->draw_arrow; +} + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return lv_label_get_text(ext->label); +} + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return ext->sel_opt_id; +} + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + uint16_t i; + uint16_t line = 0; + const char * opt_txt = lv_label_get_text(ext->label); + uint16_t txt_len = strlen(opt_txt); + + + for(i = 0; i < txt_len && line != ext->sel_opt_id; i++) { + if(opt_txt[i] == '\n') line ++; + } + + uint16_t c; + for(c = 0; opt_txt[i] != '\n' && i < txt_len; c++, i++) buf[c] = opt_txt[i]; + + buf[c] = '\0'; +} + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->action; +} + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->fix_height; +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->anim_time; +} + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t * ddlist, lv_ddlist_style_t type) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + switch(type) { + case LV_DDLIST_STYLE_BG: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_BG); + case LV_DDLIST_STYLE_BGO: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_BGO); + case LV_DDLIST_STYLE_PR: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_PR); + case LV_DDLIST_STYLE_SB: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_SB); + case LV_DDLIST_STYLE_SEL: + return ext->sel_style; + default: + return NULL; + } + + /*To avoid warning*/ + return NULL; +} + +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return lv_label_get_align(ext->label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->opened = 1; + lv_obj_set_drag(lv_page_get_scrl(ddlist), true); + lv_ddlist_refr_size(ddlist, anim_en); +} + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->opened = 0; + lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + lv_ddlist_refr_size(ddlist, anim_en); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Get the text alignment flag for a drop down list. + * @param ddlist drop down list + * @return text alignment flag + */ +static lv_txt_flag_t lv_ddlist_get_txt_flag(const lv_obj_t *ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*The label might be already deleted so just return with some value*/ + if(!ext->label) return LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(ext->label); + + switch(align) + { + default: + case LV_LABEL_ALIGN_LEFT: + return LV_TXT_FLAG_NONE; + case LV_LABEL_ALIGN_CENTER: + return LV_TXT_FLAG_CENTER; + case LV_LABEL_ALIGN_RIGHT: + return LV_TXT_FLAG_RIGHT; + } +} + +/** + * Handle the drawing related tasks of the drop down lists + * @param ddlist pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(ddlist, mask, mode); + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + ancestor_design(ddlist, mask, mode); + + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist); + /*If the list is opened draw a rectangle under the selected item*/ + if(ext->opened != 0) { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + /*Draw the selected*/ + lv_area_t rect_area; + rect_area.y1 = ext->label->coords.y1; + rect_area.y1 += ext->sel_opt_id * (font_h + style->text.line_space); + rect_area.y1 -= style->text.line_space / 2; + + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = ddlist->coords.x1; + rect_area.x2 = ddlist->coords.x2; + + lv_draw_rect(&rect_area, mask, ext->sel_style, opa_scale); + } + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + /*Redraw the text on the selected area with a different color*/ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist); + + /*Redraw only in opened state*/ + if(ext->opened) { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + lv_area_t area_sel; + area_sel.y1 = ext->label->coords.y1; + area_sel.y1 += ext->sel_opt_id * (font_h + style->text.line_space); + area_sel.y1 -= style->text.line_space / 2; + + area_sel.y2 = area_sel.y1 + font_h + style->text.line_space - 1; + area_sel.x1 = ddlist->coords.x1; + area_sel.x2 = ddlist->coords.x2; + lv_area_t mask_sel; + bool area_ok; + area_ok = lv_area_intersect(&mask_sel, mask, &area_sel); + if(area_ok) { + lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_SEL); + lv_style_t new_style; + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_txt_flag_t flag = lv_ddlist_get_txt_flag(ddlist); + lv_draw_label(&ext->label->coords, &mask_sel, &new_style, opa_scale, + lv_label_get_text(ext->label), flag, NULL); + } + } + + /*Add a down symbol in ddlist when closed*/ + else + { + /*Draw a arrow in ddlist if enabled*/ + if(ext->draw_arrow) + { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + lv_coord_t font_h = lv_font_get_height(font); + lv_style_t new_style; + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_area_t area_arrow; + area_arrow.x2 = ddlist->coords.x2 - style->body.padding.hor; + if (!ext->direction_up) + area_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_DOWN, strlen(SYMBOL_DOWN), sel_style->text.font, 0, 0); + else + area_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_UP, strlen(SYMBOL_UP), sel_style->text.font, 0, 0); + + area_arrow.y1 = ddlist->coords.y1 + style->text.line_space; + area_arrow.y2 = area_arrow.y1 + font_h; + + + lv_area_t mask_arrow; + bool area_ok; + area_ok = lv_area_intersect(&mask_arrow, mask, &area_arrow); + if (area_ok) + { + if (!ext->direction_up) + lv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale, + SYMBOL_DOWN, LV_TXT_FLAG_NONE, NULL); /*Use a down arrow in ddlist, you can replace it with your custom symbol*/ + else + lv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale, + SYMBOL_UP, LV_TXT_FLAG_NONE, NULL); /*Use a down arrow in ddlist, you can replace it with your custom symbol*/ + } + } + } + /*Draw the scrollbar in the ancestor page design function*/ + ancestor_design(ddlist, mask, mode); + } + + return true; +} + +/** + * Signal function of the drop down list + * @param ddlist pointer to a drop down list object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param) +{ + lv_res_t res; + /* Include the ancient signal function */ + res = ancestor_signal(ddlist, sign, param); + if(res != LV_RES_OK) return res; + + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if(sign == LV_SIGNAL_STYLE_CHG) { + //! lv_ddlist_refr_size(ddlist, 0); // uncommented in OG + } else if(sign == LV_SIGNAL_CLEANUP) { + ext->label = NULL; + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(ddlist); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*Open the list if editing*/ + if(editing) { + ext->opened = true; + ext->sel_opt_id_ori = ext->sel_opt_id; + lv_ddlist_refr_size(ddlist, true); + } + /*Close the lift if navigating*/ + else { + ext->opened = false; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + + } + } else { + /*Open the list if closed*/ + if(!ext->opened) { + ext->opened = true; + ext->sel_opt_id_ori = ext->sel_opt_id; /*Save the current value. Used to revert this state if ENER wont't be pressed*/ + lv_ddlist_refr_size(ddlist, true); + } + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { + if(ext->opened) { + ext->opened = false; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + if(!ext->opened) { + ext->opened = 1; + lv_ddlist_refr_size(ddlist, true); + } + + if(ext->sel_opt_id + 1 < ext->option_cnt) { + ext->sel_opt_id ++; + lv_ddlist_pos_current_option(ddlist); + lv_obj_invalidate(ddlist); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + if(!ext->opened) { + ext->opened = 1; + lv_ddlist_refr_size(ddlist, true); + } + if(ext->sel_opt_id > 0) { + ext->sel_opt_id --; + lv_ddlist_pos_current_option(ddlist); + lv_obj_invalidate(ddlist); + } + } else if(c == LV_GROUP_KEY_ENTER) { + if(ext->opened) { + ext->sel_opt_id_ori = ext->sel_opt_id; + ext->opened = 0; + if(ext->action) ext->action(ddlist); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(ddlist); + bool editing = lv_group_get_editing(g); + if(editing) lv_group_set_editing(g, false); /*In edit mode go to navigate mode if an option is selected*/ +#endif + } else { + ext->opened = 1; + } + + lv_ddlist_refr_size(ddlist, true); + } else if(c == LV_GROUP_KEY_ESC) { + if(ext->opened) { + ext->opened = 0; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_ddlist"; + } + + return res; +} + +/** + * Signal function of the drop down list's scrollable part + * @param scrl pointer to a drop down list's scrollable part + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * ddlist = lv_obj_get_parent(scrl); + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /* Because of the wider selected rectangle ext. size + * In this way by dragging the scrollable part the wider rectangle area can be redrawn too*/ + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + if(scrl->ext_size < style->body.padding.hor) scrl->ext_size = style->body.padding.hor; + } else if(sign == LV_SIGNAL_CLEANUP) { + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->label = NULL; /*The label is already deleted*/ + } + + return res; +} + +/** + * Called when a drop down list is released to open it or set new option + * @param ddlist pointer to a drop down list object + * @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK + */ +static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if (!lv_obj_get_click(ddlist)) return LV_RES_OK; + + if(ext->opened == 0) { /*Open the list*/ + ext->opened = 1; + lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO)); + lv_obj_set_drag(lv_page_get_scrl(ddlist), true); + } else { + ext->opened = 0; + //lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR))); + lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + + /*Search the clicked option*/ + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + p.x -= ext->label->coords.x1; + p.y -= ext->label->coords.y1; + uint16_t letter_i; + letter_i = lv_label_get_letter_on(ext->label, &p); + + uint16_t new_opt = 0; + const char * txt = lv_label_get_text(ext->label); + uint32_t i = 0; + uint32_t line_cnt = 0; + uint32_t letter; + for(line_cnt = 0; line_cnt < letter_i; line_cnt++) { + letter = lv_txt_encoded_next(txt, &i); + if(letter == '\n') new_opt ++; + } + + ext->sel_opt_id = new_opt; + + if(ext->action != NULL) { + ext->action(ddlist); + } + } + lv_ddlist_refr_size(ddlist, true); + + return LV_RES_OK; +} + +static lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if (!lv_obj_get_click(ddlist)) return LV_RES_OK; + + if (ext->opened == 0) + { /*Open the list*/ + lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR)); + } + else + { + //lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO)); + //lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + + ///*Search the clicked option*/ + //lv_indev_t * indev = lv_indev_get_act(); + //lv_point_t p; + //lv_indev_get_point(indev, &p); + //p.x -= ext->label->coords.x1; + //p.y -= ext->label->coords.y1; + //uint16_t letter_i; + //letter_i = lv_label_get_letter_on(ext->label, &p); + + //uint16_t new_opt = 0; + //const char * txt = lv_label_get_text(ext->label); + //uint32_t i = 0; + //uint32_t line_cnt = 0; + //uint32_t letter; + //for (line_cnt = 0; line_cnt < letter_i; line_cnt++) + //{ + // letter = lv_txt_encoded_next(txt, &i); + // if (letter == '\n') new_opt++; + //} + + //ext->sel_opt_id = new_opt; + + //if (ext->action != NULL) + //{ + // ext->action(ddlist); + //} + } + + return LV_RES_OK; +} + +/** + * Refresh the size of drop down list according to its status (open or closed) + * @param ddlist pointer to a drop down list object + * @param anim_en Change the size (open/close) with or without animation (true/false) + */ +static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_style_t * style = lv_obj_get_style(ddlist); + lv_coord_t new_height, full_height; + bool current_state = 0; + + if(ext->opened) { /*Open the list*/ + if(ext->fix_height == 0) new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver; + else new_height = ext->fix_height; + current_state = 1; + + lv_page_set_sb_mode(ddlist, LV_SB_MODE_UNHIDE); + } else { /*Close the list*/ + const lv_font_t * font = style->text.font; + lv_style_t * label_style = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(font); + new_height = font_h + 2 * label_style->text.line_space; + //full_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver; + current_state = 0; + + lv_page_set_sb_mode(ddlist, LV_SB_MODE_HIDE); + } + + if(anim_en == 0 || ext->direction_up) { + lv_obj_set_height(ddlist, new_height); + if (ext->direction_up) + { + full_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) - lv_font_get_height(style->text.font); + if (current_state) + lv_obj_set_y(ddlist, lv_obj_get_y(ddlist) - full_height); + else + lv_obj_set_y(ddlist, lv_obj_get_y(ddlist) + full_height); + } + + lv_ddlist_pos_current_option(ddlist); +#if USE_LV_ANIMATION + lv_anim_del(ddlist, (lv_anim_fp_t)lv_obj_set_height); /*If an animation is in progress then it will overwrite this changes*/ + } else { + lv_anim_t a; + a.var = ddlist; + a.start = lv_obj_get_height(ddlist); + a.end = new_height; + a.fp = (lv_anim_fp_t)lv_obj_set_height; + a.path = lv_anim_path_linear; + a.end_cb = (lv_anim_cb_t)lv_ddlist_pos_current_option; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + lv_anim_create(&a); +#endif + } +} + +/** + * Set the position of list when it is closed to show the selected item + * @param ddlist pointer to a drop down list + */ +static void lv_ddlist_pos_current_option(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_style_t * style = lv_obj_get_style(ddlist); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_style_t * label_style = lv_obj_get_style(ext->label); + lv_obj_t * scrl = lv_page_get_scrl(ddlist); + + lv_coord_t h = lv_obj_get_height(ddlist); + lv_coord_t line_y1 = ext->sel_opt_id * (font_h + label_style->text.line_space) + ext->label->coords.y1 - scrl->coords.y1; + + lv_obj_set_y(scrl, - line_y1 + (h - font_h) / 2); +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_ddlist.h b/bdk/libs/lvgl/lv_objx/lv_ddlist.h new file mode 100644 index 0000000..db00080 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_ddlist.h @@ -0,0 +1,286 @@ +/* + * 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 . + */ + +/** + * @file lv_ddlist.h + * + */ + +#ifndef LV_DDLIST_H +#define LV_DDLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_DDLIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_page.h" +#include "../lv_objx/lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of drop down list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *label; /*Label for the options*/ + lv_style_t * sel_style; /*Style of the selected option*/ + lv_action_t action; /*Pointer to function to call when an option is selected*/ + uint16_t option_cnt; /*Number of options*/ + uint16_t sel_opt_id; /*Index of the current option*/ + uint16_t sel_opt_id_ori; /*Store the original index on focus*/ + uint16_t anim_time; /*Open/Close animation time [ms]*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + uint8_t draw_arrow :1; /*1: Draw arrow*/ + uint8_t direction_up : 1; /*1: Open direction*/ + + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ +} lv_ddlist_ext_t; + +enum { + LV_DDLIST_STYLE_BG, + LV_DDLIST_STYLE_BGO, + LV_DDLIST_STYLE_PR, + LV_DDLIST_STYLE_SEL, + LV_DDLIST_STYLE_SB, +}; +typedef uint8_t lv_ddlist_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en); + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options); + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt); + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action); + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h); + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en); + +/** + * Set the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ddlist, mode); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time); + + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style); + +/** + * Set the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @param align alignment of labels + */ +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align); + +void lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist); + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist); + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist); + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf); + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist); + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist); + +/** + * Get the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist) +{ + return lv_page_get_sb_mode(ddlist); +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist); + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type); + +/** + * Get the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @return alignment of labels + */ +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en); + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_DDLIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DDLIST_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_gauge.c b/bdk/libs/lvgl/lv_objx/lv_gauge.c new file mode 100644 index 0000000..ad2ef8d --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_gauge.c @@ -0,0 +1,466 @@ +/** + * @file lv_gauge.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_gauge.h" +#if USE_LV_GAUGE != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_GAUGE_DEF_NEEDLE_COLOR LV_COLOR_RED +#define LV_GAUGE_DEF_LABEL_COUNT 6 +#define LV_GAUGE_DEF_LINE_COUNT 21 /*Should be: ((label_cnt - 1) * internal_lines) + 1*/ +#define LV_GAUGE_DEF_ANGLE 220 +#define LV_GAUGE_INTERPOLATE_SHIFT 5 /*Interpolate the needle drawing between to degrees*/ +#define LV_GAUGE_INTERPOLATE_MASK 0x1F + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param); +static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask); +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("gauge create started"); + + /*Create the ancestor gauge*/ + lv_obj_t * new_gauge = lv_lmeter_create(par, copy); + lv_mem_assert(new_gauge); + if(new_gauge == NULL) return NULL; + + /*Allocate the gauge type specific extended data*/ + lv_gauge_ext_t * ext = lv_obj_allocate_ext_attr(new_gauge, sizeof(lv_gauge_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->needle_count = 0; + ext->values = NULL; + ext->needle_colors = NULL; + ext->label_count = LV_GAUGE_DEF_LABEL_COUNT; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_gauge); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_gauge); + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_gauge, lv_gauge_signal); + lv_obj_set_design_func(new_gauge, lv_gauge_design); + + /*Init the new gauge gauge*/ + if(copy == NULL) { + lv_gauge_set_scale(new_gauge, LV_GAUGE_DEF_ANGLE, LV_GAUGE_DEF_LINE_COUNT, LV_GAUGE_DEF_LABEL_COUNT); + lv_gauge_set_needle_count(new_gauge, 1, NULL); + lv_gauge_set_critical_value(new_gauge, 80); + lv_obj_set_size(new_gauge, 2 * LV_DPI, 2 * LV_DPI); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_gauge_set_style(new_gauge, th->gauge); + } else { + lv_gauge_set_style(new_gauge, &lv_style_pretty_color); + } + } + /*Copy an existing gauge*/ + else { + lv_gauge_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_gauge_set_needle_count(new_gauge, copy_ext->needle_count, copy_ext->needle_colors); + + uint8_t i; + for(i = 0; i < ext->needle_count; i++) { + ext->values[i] = copy_ext->values[i]; + } + ext->label_count = copy_ext->label_count; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_gauge); + } + + LV_LOG_INFO("gauge created"); + + return new_gauge; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + if(ext->needle_count != needle_cnt) { + if(ext->values != NULL) { + lv_mem_free(ext->values); + ext->values = NULL; + } + + ext->values = lv_mem_realloc(ext->values, needle_cnt * sizeof(int16_t)); + lv_mem_assert(ext->values); + if(ext->values == NULL) return; + + int16_t min = lv_gauge_get_min_value(gauge); + uint8_t n; + for(n = ext->needle_count; n < needle_cnt; n++) { + ext->values[n] = min; + } + + ext->needle_count = needle_cnt; + } + + ext->needle_colors = colors; + lv_obj_invalidate(gauge); +} + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + if(needle_id >= ext->needle_count) return; + if(ext->values[needle_id] == value) return; + + + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + + if(value > max) value = max; + else if(value < min) value = min; + + ext->values[needle_id] = value; + + + lv_obj_invalidate(gauge); +} + + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt) +{ + /*TODO v6.0: change `line_cnt` to `subdiv_cnt`*/ + + lv_lmeter_set_scale(gauge, angle, line_cnt); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + ext->label_count = label_cnt; + lv_obj_invalidate(gauge); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + int16_t min = lv_gauge_get_min_value(gauge); + + if(needle >= ext->needle_count) return min; + + return ext->values[needle]; +} + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + return ext->needle_count; +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + return ext->label_count; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the gauges + * @param gauge pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode) +{ + + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + /* Store the real pointer because of 'lv_group' + * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style + * and to the real object style. It is important because of style change tricks below*/ + lv_style_t * style_ori_p = gauge->style_p; + lv_style_t * style = lv_obj_get_style(gauge); + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + lv_gauge_draw_scale(gauge, mask); + + /*Draw the ancestor line meter with max value to show the rainbow like line colors*/ + uint16_t line_cnt_tmp = ext->lmeter.line_cnt; + ancestor_design(gauge, mask, mode); /*To draw lines*/ + + /*Temporally modify the line meter to draw thicker and longer lines where labels are*/ + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style); + ext->lmeter.line_cnt = ext->label_count; /*Only to labels*/ + style_tmp.line.width = style_tmp.line.width * 2; /*Ticker lines*/ + style_tmp.body.padding.hor = style_tmp.body.padding.hor * 2; /*Longer lines*/ + gauge->style_p = &style_tmp; + + ancestor_design(gauge, mask, mode); /*To draw lines*/ + + ext->lmeter.line_cnt = line_cnt_tmp; /*Restore the parameters*/ + gauge->style_p = style_ori_p; /*Restore the ORIGINAL style pointer*/ + + lv_gauge_draw_needle(gauge, mask); + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(gauge, mask, mode); + } + + return true; +} + +/** + * Signal function of the gauge + * @param gauge pointer to a gauge object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(gauge, sign, param); + if(res != LV_RES_OK) return res; + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + if(sign == LV_SIGNAL_CLEANUP) { + lv_mem_free(ext->values); + ext->values = NULL; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_gauge"; + } + + return res; +} + +/** + * Draw the scale on a gauge + * @param gauge pointer to gauge object + * @param mask mask of drawing + */ +static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask) +{ + char scale_txt[16]; + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + lv_style_t * style = lv_obj_get_style(gauge); + lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge); + lv_coord_t r = lv_obj_get_width(gauge) / 2 - (3 * style->body.padding.hor) - style->body.padding.inner; + lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1; + int16_t scale_angle = lv_lmeter_get_scale_angle(gauge); + uint16_t label_num = ext->label_count; + int16_t angle_ofs = 90 + (360 - scale_angle) / 2; + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + + uint8_t i; + for(i = 0; i < label_num; i++) { + /*Calculate the position a scale label*/ + int16_t angle = (i * scale_angle) / (label_num - 1) + angle_ofs; + + lv_coord_t y = (int32_t)((int32_t)lv_trigo_sin(angle) * r) / LV_TRIGO_SIN_MAX; + y += y_ofs; + + lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX; + x += x_ofs; + + int16_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1); + scale_act += min; + lv_math_num_to_str(scale_act, scale_txt); + + lv_area_t label_cord; + lv_point_t label_size; + lv_txt_get_size(&label_size, scale_txt, style->text.font, + style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + + /*Draw the label*/ + label_cord.x1 = x - label_size.x / 2; + label_cord.y1 = y - label_size.y / 2; + label_cord.x2 = label_cord.x1 + label_size.x; + label_cord.y2 = label_cord.y1 + label_size.y; + + lv_draw_label(&label_cord, mask, style, opa_scale, scale_txt, LV_TXT_FLAG_NONE, NULL); + } +} +/** + * Draw the needles of a gauge + * @param gauge pointer to gauge object + * @param mask mask of drawing + */ +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask) +{ + lv_style_t style_needle; + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + lv_style_t * style = lv_gauge_get_style(gauge); + lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge); + + lv_coord_t r = lv_obj_get_width(gauge) / 2 - style->body.padding.hor; + lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1; + uint16_t angle = lv_lmeter_get_scale_angle(gauge); + int16_t angle_ofs = 90 + (360 - angle) / 2; + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + lv_point_t p_mid; + lv_point_t p_end; + lv_point_t p_end_low; + lv_point_t p_end_high; + uint8_t i; + + lv_style_copy(&style_needle, style); + + p_mid.x = x_ofs; + p_mid.y = y_ofs; + for(i = 0; i < ext->needle_count; i++) { + /*Calculate the end point of a needle*/ + int16_t needle_angle = (ext->values[i] - min) * angle * (1 << LV_GAUGE_INTERPOLATE_SHIFT) / (max - min); //+ angle_ofs; + + + int16_t needle_angle_low = (needle_angle >> LV_GAUGE_INTERPOLATE_SHIFT) + angle_ofs; + int16_t needle_angle_high = needle_angle_low + 1; + + + p_end_low.y = (lv_trigo_sin(needle_angle_low) * r) / LV_TRIGO_SIN_MAX + y_ofs; + p_end_low.x = (lv_trigo_sin(needle_angle_low + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + + p_end_high.y = (lv_trigo_sin(needle_angle_high) * r) / LV_TRIGO_SIN_MAX + y_ofs; + p_end_high.x = (lv_trigo_sin(needle_angle_high + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + + uint16_t rem = needle_angle & ((1 << LV_GAUGE_INTERPOLATE_SHIFT) - 1); + int16_t x_mod = ((LV_MATH_ABS(p_end_high.x - p_end_low.x)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; + int16_t y_mod = ((LV_MATH_ABS(p_end_high.y - p_end_low.y)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; + + if(p_end_high.x < p_end_low.x) x_mod = -x_mod; + if(p_end_high.y < p_end_low.y) y_mod = -y_mod; + + p_end.x = p_end_low.x + x_mod; + p_end.y = p_end_low.y + y_mod; + + /*Draw the needle with the corresponding color*/ + if(ext->needle_colors == NULL) style_needle.line.color = LV_GAUGE_DEF_NEEDLE_COLOR; + else style_needle.line.color = ext->needle_colors[i]; + + lv_draw_line(&p_mid, &p_end, mask, &style_needle, opa_scale); + } + + /*Draw the needle middle area*/ + lv_style_t style_neddle_mid; + lv_style_copy(&style_neddle_mid, &lv_style_plain); + style_neddle_mid.body.main_color = style->body.border.color; + style_neddle_mid.body.grad_color = style->body.border.color; + style_neddle_mid.body.radius = LV_RADIUS_CIRCLE; + + lv_area_t nm_cord; + nm_cord.x1 = x_ofs - style->body.padding.ver; + nm_cord.y1 = y_ofs - style->body.padding.ver; + nm_cord.x2 = x_ofs + style->body.padding.ver; + nm_cord.y2 = y_ofs + style->body.padding.ver; + + lv_draw_rect(&nm_cord, mask, &style_neddle_mid, lv_obj_get_opa_scale(gauge)); +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_gauge.h b/bdk/libs/lvgl/lv_objx/lv_gauge.h new file mode 100644 index 0000000..beef9dc --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_gauge.h @@ -0,0 +1,222 @@ +/** + * @file lv_gauge.h + * + */ + +#ifndef LV_GAUGE_H +#define LV_GAUGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_GAUGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LMETER == 0 +#error "lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_lmeter.h" +#include "lv_label.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of gauge*/ +typedef struct +{ + lv_lmeter_ext_t lmeter; /*Ext. of ancestor*/ + /*New data for this type */ + int16_t * values; /*Array of the set values (for needles) */ + const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + uint8_t needle_count; /*Number of needles*/ + uint8_t label_count; /*Number of labels on the scale*/ +} lv_gauge_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors); + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); + +/** + * Set minimum and the maximum values of a gauge + * @param gauge pointer to he gauge object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max) +{ + lv_lmeter_set_range(gauge, min, max); +} + +/** + * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn + * @param gauge pointer to a gauge object + * @param value the critical value + */ +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +{ + lv_lmeter_set_value(gauge, value); +} + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); + +/** + * Set the styles of a gauge + * @param gauge pointer to a gauge object + * @param bg set the style of the gauge + * */ +static inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg) +{ + lv_obj_set_style(gauge, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); + +/** + * Get the minimum value of a gauge + * @param gauge pointer to a gauge object + * @return the minimum value of the gauge + */ +static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_min_value(lmeter); +} + +/** + * Get the maximum value of a gauge + * @param gauge pointer to a gauge object + * @return the maximum value of the gauge + */ +static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_max_value(lmeter); +} + +/** + * Get a critical value on the scale. + * @param gauge pointer to a gauge object + * @return the critical value + */ +static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +{ + return lv_lmeter_get_value(gauge); +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge); + +/** + * Get the scale number of a gauge + * @param gauge pointer to a gauge object + * @return number of the scale units + */ +static inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge) +{ + return lv_lmeter_get_line_count(gauge); +} + +/** + * Get the scale angle of a gauge + * @param gauge pointer to a gauge object + * @return angle of the scale + */ +static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) +{ + return lv_lmeter_get_scale_angle(gauge); +} + +/** + * Get the style of a gauge + * @param gauge pointer to a gauge object + * @return pointer to the gauge's style + */ +static inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge) +{ + return lv_obj_get_style(gauge); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GAUGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GAUGE_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_img.c b/bdk/libs/lvgl/lv_objx/lv_img.c new file mode 100644 index 0000000..c9fb428 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_img.c @@ -0,0 +1,408 @@ +/** + * @file lv_img.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_img.h" +#if USE_LV_IMG != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_img: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_lang.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_ufs.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("image create started"); + + lv_obj_t * new_img = NULL; + + /*Create a basic object*/ + new_img = lv_obj_create(par, copy); + lv_mem_assert(new_img); + if(new_img == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_img); + + /*Extend the basic object to image object*/ + lv_img_ext_t * ext = lv_obj_allocate_ext_attr(new_img, sizeof(lv_img_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + ext->cf = LV_IMG_CF_UNKOWN; + ext->w = lv_obj_get_width(new_img); + ext->h = lv_obj_get_height(new_img); + ext->auto_size = 1; +#if USE_LV_MULTI_LANG + ext->lang_txt_id = LV_LANG_TXT_ID_NONE; +#endif + + /*Init the new object*/ + lv_obj_set_signal_func(new_img, lv_img_signal); + lv_obj_set_design_func(new_img, lv_img_design); + + if(copy == NULL) { + lv_obj_set_click(new_img, false); + /* Enable auto size for non screens + * because image screens are wallpapers + * and must be screen sized*/ + if(par != NULL) { + ext->auto_size = 1; + lv_obj_set_style(new_img, NULL); /*Inherit the style by default*/ + } else { + ext->auto_size = 0; + lv_obj_set_style(new_img, &lv_style_plain); /*Set a style for screens*/ + } + } else { + lv_img_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->auto_size = copy_ext->auto_size; + lv_img_set_src(new_img, copy_ext->src); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_img); + } + + + LV_LOG_INFO("image created"); + + return new_img; +} + + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img) +{ + lv_img_src_t src_type = lv_img_src_get_type(src_img); + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + +#if LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO + switch(src_type) { + case LV_IMG_SRC_FILE: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_FILE` type found"); + break; + case LV_IMG_SRC_VARIABLE: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found"); + break; + case LV_IMG_SRC_SYMBOL: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found"); + break; + default: + LV_LOG_WARN("lv_img_set_src: unknown type"); + } +#endif + + /*If the new source type is unknown free the memories of the old source*/ + if(src_type == LV_IMG_SRC_UNKNOWN) { + LV_LOG_WARN("lv_img_set_src: unknown image type"); + if(ext->src_type == LV_IMG_SRC_SYMBOL || ext->src_type == LV_IMG_SRC_FILE) { + lv_mem_free(ext->src); + } + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + return; + } + + lv_img_header_t header; + lv_img_dsc_get_info(src_img, &header); + + + + /*Save the source*/ + if(src_type == LV_IMG_SRC_VARIABLE) { + LV_LOG_INFO("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found"); + + /*If memory was allocated because of the previous `src_type` then free it*/ + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + } + ext->src = src_img; + } else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) { + /* If the new and the old src are the same then it was only a refresh.*/ + if(ext->src != src_img) { + /*If memory was allocated because of the previous `src_type` then free it*/ + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + } + char * new_str = lv_mem_alloc(strlen(src_img) + 1); + lv_mem_assert(new_str); + if(new_str == NULL) return; + strcpy(new_str, src_img); + ext->src = new_str; + } + } + + if(src_type == LV_IMG_SRC_SYMBOL) { + /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/ + lv_style_t * style = lv_img_get_style(img); + lv_point_t size; + lv_txt_get_size(&size, src_img, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + header.w = size.x; + header.h = size.y; + } + + ext->src_type = src_type; + ext->w = header.w; + ext->h = header.h; + ext->cf = header.cf; + + if(lv_img_get_auto_size(img) != false) { + lv_obj_set_size(img, ext->w, ext->h); + } + + lv_obj_invalidate(img); +} + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but in different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t src_id) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + ext->lang_txt_id = src_id; + + /*Apply the new language*/ + img->signal_func(img, LV_SIGNAL_LANG_CHG, NULL); +} +#endif + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool en) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + ext->auto_size = (en == false ? 0 : 1); +} + + +/*===================== + * Getter functions + *====================*/ + + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + return ext->src; +} + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + if(ext->src_type == LV_IMG_SRC_FILE) return ext->src; + else return ""; +} + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + return ext->lang_txt_id; +} +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + return ext->auto_size == 0 ? false : true; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the images + * @param img pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode) +{ + lv_style_t * style = lv_obj_get_style(img); + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + if(mode == LV_DESIGN_COVER_CHK) { + bool cover = false; + if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL) return false; + + if(ext->cf == LV_IMG_CF_TRUE_COLOR || ext->cf == LV_IMG_CF_RAW) cover = lv_area_is_in(mask, &img->coords); + + return cover; + } else if(mode == LV_DESIGN_DRAW_MAIN) { + if(ext->h == 0 || ext->w == 0) return true; + lv_area_t coords; + lv_opa_t opa_scale = lv_obj_get_opa_scale(img); + + lv_obj_get_coords(img, &coords); + + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_VARIABLE) { + LV_LOG_TRACE("lv_img_design: start to draw image"); + lv_area_t cords_tmp; + cords_tmp.y1 = coords.y1; + cords_tmp.y2 = coords.y1 + ext->h - 1; + + for(; cords_tmp.y1 < coords.y2; cords_tmp.y1 += ext->h, cords_tmp.y2 += ext->h) { + cords_tmp.x1 = coords.x1; + cords_tmp.x2 = coords.x1 + ext->w - 1; + for(; cords_tmp.x1 < coords.x2; cords_tmp.x1 += ext->w, cords_tmp.x2 += ext->w) { + lv_draw_img(&cords_tmp, mask, ext->src, style, opa_scale); + } + } + } else if(ext->src_type == LV_IMG_SRC_SYMBOL) { + LV_LOG_TRACE("lv_img_design: start to draw symbol"); + lv_style_t style_mod; + lv_style_copy(&style_mod, style); + style_mod.text.color = style->image.color; + lv_draw_label(&coords, mask, &style_mod, opa_scale, ext->src, LV_TXT_FLAG_NONE, NULL); + } else { + /*Trigger the error handler of image drawer*/ + LV_LOG_WARN("lv_img_design: image source type is unknown"); + lv_draw_img(&img->coords, mask, NULL, style, opa_scale); + } + } + + return true; +} + + +/** + * Signal function of the image + * @param img pointer to an image object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(img, sign, param); + if(res != LV_RES_OK) return res; + + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Refresh the file name to refresh the symbol text size*/ + if(ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_img_set_src(img, ext->src); + + } + } else if(sign == LV_SIGNAL_LANG_CHG) { +#if USE_LV_MULTI_LANG + if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) { + const char * lang_src = lv_lang_get_text(ext->lang_txt_id); + if(lang_src) { + lv_img_set_src(img, lang_src); + } else { + LV_LOG_WARN("lv_lang_get_text return NULL for an image's source"); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_img"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_img.h b/bdk/libs/lvgl/lv_objx/lv_img.h new file mode 100644 index 0000000..8ee8616 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_img.h @@ -0,0 +1,195 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_IMG != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_symbol_def.h" +#include "lv_label.h" +#include "../lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image*/ +typedef struct +{ + /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/ + /*New data for this type */ + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the image to display. */ +#endif + uint8_t src_type :2; /*See: lv_img_src_t*/ + uint8_t auto_size :1; /*1: automatically set the object size to the image size*/ + uint8_t cf :5; /*Color format from `lv_img_color_format_t`*/ +} lv_img_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img); + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but on different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id); +#endif + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0. + * Use 'lv_img_set_src()' instead. + * @param img - + * @param fn - + */ +static inline void lv_img_set_file(lv_obj_t * img, const char * fn) +{ + (void) img; + (void) fn; +} + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en); + +/** + * Set the style of an image + * @param img pointer to an image object + * @param style pointer to a style + */ +static inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style) +{ + lv_obj_set_style(img, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @param upscale - + */ +static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale) +{ + (void) img; + (void) upcale; +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img); + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img); + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img); +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img); + +/** + * Get the style of an image object + * @param img pointer to an image object + * @return pointer to the image's style + */ +static inline lv_style_t* lv_img_get_style(const lv_obj_t *img) +{ + return lv_obj_get_style(img); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @return false + */ +static inline bool lv_img_get_upscale(const lv_obj_t * img) +{ + (void)img; + return false; +} + +/********************** + * MACROS + **********************/ + +/*Use this macro to declare an image in a c file*/ +#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; + +#endif /*USE_LV_IMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_imgbtn.c b/bdk/libs/lvgl/lv_objx/lv_imgbtn.c new file mode 100644 index 0000000..ed1d72b --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_imgbtn.c @@ -0,0 +1,391 @@ +/** + * @file lv_imgbtn.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_imgbtn.h" +#if USE_LV_IMGBTN != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param); +static void refr_img(lv_obj_t * imgbtn); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a image button object + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("image button create started"); + + /*Create the ancestor of image button*/ + lv_obj_t * new_imgbtn = lv_btn_create(par, copy); + lv_mem_assert(new_imgbtn); + if(new_imgbtn == NULL) return NULL; + + /*Allocate the image button type specific extended data*/ + lv_imgbtn_ext_t * ext = lv_obj_allocate_ext_attr(new_imgbtn, sizeof(lv_imgbtn_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_imgbtn); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_imgbtn); + + /*Initialize the allocated 'ext' */ +#if LV_IMGBTN_TILED == 0 + memset(ext->img_src, 0, sizeof(ext->img_src)); +#else + memset(ext->img_src_left, 0, sizeof(ext->img_src_left)); + memset(ext->img_src_mid, 0, sizeof(ext->img_src_mid)); + memset(ext->img_src_right, 0, sizeof(ext->img_src_right)); +#endif + + ext->act_cf = LV_IMG_CF_UNKOWN; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_imgbtn, lv_imgbtn_signal); + lv_obj_set_design_func(new_imgbtn, lv_imgbtn_design); + + /*Init the new image button image button*/ + if(copy == NULL) { + + } + /*Copy an existing image button*/ + else { + lv_imgbtn_ext_t * copy_ext = lv_obj_get_ext_attr(copy); +#if LV_IMGBTN_TILED == 0 + memcpy(ext->img_src, copy_ext->img_src, sizeof(ext->img_src)); +#else + memcpy(ext->img_src_left, copy_ext->img_src_left, sizeof(ext->img_src_left)); + memcpy(ext->img_src_mid, copy_ext->img_src_mid, sizeof(ext->img_src_mid)); + memcpy(ext->img_src_right, copy_ext->img_src_right, sizeof(ext->img_src_right)); +#endif + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_imgbtn); + } + + LV_LOG_INFO("image button created"); + + return new_imgbtn; +} + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + ext->img_src[state] = src; + + refr_img(imgbtn); +} + +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + ext->img_src_left[state] = src_left; + ext->img_src_mid[state] = src_mid; + ext->img_src_right[state] = src_right; + + refr_img(imgbtn); +} + +#endif + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t * style) +{ + lv_btn_set_style(imgbtn, type, style); +} + +/*===================== + * Getter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src[state]; +} +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_left[state]; +} + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_mid[state]; +} + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_right[state]; +} + +#endif + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type) +{ + return lv_btn_get_style(imgbtn, type); +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the image buttons + * @param imgbtn pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + bool cover = false; + if(ext->act_cf == LV_IMG_CF_TRUE_COLOR || ext->act_cf == LV_IMG_CF_RAW) { + cover = lv_area_is_in(mask, &imgbtn->coords); + } + + return cover; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Just draw an image*/ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + lv_btn_state_t state = lv_imgbtn_get_state(imgbtn); + lv_style_t * style = lv_imgbtn_get_style(imgbtn, state); + lv_opa_t opa_scale = lv_obj_get_opa_scale(imgbtn); + +#if LV_IMGBTN_TILED == 0 + const void * src = ext->img_src[state]; + lv_draw_img(&imgbtn->coords, mask, src, style, opa_scale); +#else + const void * src; + lv_img_header_t header; + lv_area_t coords; + lv_coord_t left_w = 0; + lv_coord_t right_w = 0; + + src = ext->img_src_left[state]; + if(src) { + lv_img_dsc_get_info(src, &header); + left_w = header.w; + coords.x1 = imgbtn->coords.x1; + coords.y1 = imgbtn->coords.y1; + coords.x2 = coords.x1 + header.w - 1; + coords.y2 = coords.y1 + header.h - 1; + lv_draw_img(&coords, mask, src, style, opa_scale); + } + + src = ext->img_src_right[state]; + if(src) { + lv_img_dsc_get_info(src, &header); + right_w = header.w; + coords.x1 = imgbtn->coords.x2 - header.w + 1; + coords.y1 = imgbtn->coords.y1; + coords.x2 = imgbtn->coords.x2; + coords.y2 = imgbtn->coords.y1 + header.h - 1; + lv_draw_img(&coords, mask, src, style, opa_scale); + } + + src = ext->img_src_mid[state]; + if(src) { + lv_coord_t obj_w = lv_obj_get_width(imgbtn); + lv_coord_t i; + lv_img_dsc_get_info(src, &header); + + coords.x1 = imgbtn->coords.x1 + left_w ; + coords.y1 = imgbtn->coords.y1; + coords.x2 = coords.x1 + header.w - 1; + coords.y2 = imgbtn->coords.y1 + header.h - 1; + + for(i = 0; i < obj_w - right_w - left_w; i += header.w) { + lv_draw_img(&coords, mask, src, style, opa_scale); + coords.x1 = coords.x2 + 1; + coords.x2 += header.w; + } + } + + +#endif + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the image button + * @param imgbtn pointer to a image button object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(imgbtn, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_STYLE_CHG) { + /* If the style changed then the button was clicked, released etc. so probably the state was changed as well + * Set the new image for the new state.*/ + refr_img(imgbtn); + } else if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_imgbtn"; + } + + return res; +} + + +static void refr_img(lv_obj_t * imgbtn) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + lv_btn_state_t state = lv_imgbtn_get_state(imgbtn); + lv_img_header_t header; + +#if LV_IMGBTN_TILED == 0 + const void * src = ext->img_src[state]; +#else + const void * src = ext->img_src_mid[state]; +#endif + + lv_res_t info_res; + info_res = lv_img_dsc_get_info(src, &header); + if(info_res == LV_RES_OK) { + ext->act_cf = header.cf; +#if LV_IMGBTN_TILED == 0 + lv_obj_set_size(imgbtn, header.w, header.h); +#else + lv_obj_set_height(imgbtn, header.h); +#endif + } else { + ext->act_cf = LV_IMG_CF_UNKOWN; + } + + lv_obj_invalidate(imgbtn); +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_imgbtn.h b/bdk/libs/lvgl/lv_objx/lv_imgbtn.h new file mode 100644 index 0000000..300e7b8 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_imgbtn.h @@ -0,0 +1,249 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_IMGBTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btn.h" +#include "../lv_draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_btn_ext_t btn; /*Ext. of ancestor*/ + /*New data for this type */ + int idx; +#if LV_IMGBTN_TILED == 0 + const void * img_src[LV_BTN_STATE_NUM]; /*Store images to each state*/ +#else + const void * img_src_left[LV_BTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_mid[LV_BTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_right[LV_BTN_STATE_NUM]; /*Store right side images to each state*/ +#endif + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_ext_t; + + +/*Styles*/ +enum { + LV_IMGBTN_STYLE_REL, + LV_IMGBTN_STYLE_PR, + LV_IMGBTN_STYLE_TGL_REL, + LV_IMGBTN_STYLE_TGL_PR, + LV_IMGBTN_STYLE_INA, +}; +typedef uint8_t lv_imgbtn_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a image button objects + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src); +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right); + +#endif + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param imgbtn pointer to an image button object + * @param tgl true: enable toggled states, false: disable + */ +static inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl) +{ + lv_btn_set_toggle(imgbtn, tgl); +} + +/** + * Set the state of the image button + * @param imgbtn pointer to an image button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +static inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_btn_set_state(imgbtn, state); +} + +/** + * Toggle the state of the image button (ON->OFF, OFF->ON) + * @param imgbtn pointer to a image button object + */ +static inline void lv_imgbtn_toggle(lv_obj_t * imgbtn) +{ + lv_btn_toggle(imgbtn); +} + +/** + * Set a function to call when a button event happens + * @param imgbtn pointer to an image button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +static inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action) +{ + lv_btn_set_action(imgbtn, type, action); +} + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state); + +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state); + +#endif +/** + * Get the current state of the image button + * @param imgbtn pointer to a image button object + * @return the state of the button (from lv_btn_state_t enum) + */ +static inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn) +{ + return lv_btn_get_state(imgbtn); +} + +/** + * Get the toggle enable attribute of the image button + * @param imgbtn pointer to a image button object + * @return ture: toggle enabled, false: disabled + */ +static inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn) +{ + return lv_btn_get_toggle(imgbtn); +} + +/** + * Get the release action of a image button + * @param imgbtn pointer to a image button object + * @return pointer to the release action function + */ +static inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type) +{ + return lv_btn_get_action(imgbtn, type); +} + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_IMGBTN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_kb.c b/bdk/libs/lvgl/lv_objx/lv_kb.c new file mode 100644 index 0000000..8548d55 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_kb.c @@ -0,0 +1,488 @@ +/* + * 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 . + */ + +/** + * @file lv_kb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_kb.h" +#if USE_LV_KB != 0 + +#include "lv_ta.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param); +static lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +static const char * kb_map_lc[] = { + "\2051#", "\204q", "\204w", "\204e", "\204r", "\204t", "\204y", "\204u", "\204i", "\204o", "\204p", "\207Bksp", "\n", + "\226ABC", "\203a", "\203s", "\203d", "\203f", "\203g", "\203h", "\203j", "\203k", "\203l", "\207Enter", "\n", + "_", "-", "z", "x", "c", "v", "b", "n", "m", ".", ",", ":", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_uc[] = { + "\2051#", "\204Q", "\204W", "\204E", "\204R", "\204T", "\204Y", "\204U", "\204I", "\204O", "\204P", "\207Bksp", "\n", + "\226abc", "\203A", "\203S", "\203D", "\203F", "\203G", "\203H", "\203J", "\203K", "\203L", "\207Enter", "\n", + "_", "-", "Z", "X", "C", "V", "B", "N", "M", ".", ",", ":", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_spec[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "\202Bksp", "\n", + "\222abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">", "\n", + "\\", "@", "$", "(", ")", "{", "}", "[", "]", ";", "\"", "'", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_num[] = { + "1", "2", "3", "\202"SYMBOL_CLOSE, "\n", + "4", "5", "6", "\202"SYMBOL_OK, "\n", + "7", "8", "9", "\202Bksp", "\n", + "+/-", "0", ".", SYMBOL_LEFT, SYMBOL_RIGHT, "" +}; + +static const char * kb_map_hex[] = { + "1", "2", "3", "A", "D", "\212", "\n", + "4", "5", "6", "B", "E", "\202Bksp", "\n", + "7", "8", "9", "C", "F", "\202"SYMBOL_OK, "\n", + "\211", "0", "\213", SYMBOL_LEFT, SYMBOL_RIGHT, "" +}; +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("keyboard create started"); + + /*Create the ancestor of keyboard*/ + lv_obj_t * new_kb = lv_btnm_create(par, copy); + lv_mem_assert(new_kb); + if(new_kb == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_kb); + + /*Allocate the keyboard type specific extended data*/ + lv_kb_ext_t * ext = lv_obj_allocate_ext_attr(new_kb, sizeof(lv_kb_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + + ext->ta = NULL; + ext->mode = LV_KB_MODE_TEXT; + ext->cursor_mng = 0; + ext->hide_action = NULL; + ext->ok_action = NULL; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_kb, lv_kb_signal); + + /*Init the new keyboard keyboard*/ + if(copy == NULL) { + lv_obj_set_size(new_kb, LV_HOR_RES, LV_VER_RES / 2); + lv_obj_align(new_kb, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_btnm_set_action(new_kb, lv_kb_def_action); + lv_btnm_set_map(new_kb, kb_map_lc); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_kb_set_style(new_kb, LV_KB_STYLE_BG, th->kb.bg); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_REL, th->kb.btn.rel); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_PR, th->kb.btn.pr); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_REL, th->kb.btn.tgl_rel); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_PR, th->kb.btn.tgl_pr); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_INA, th->kb.btn.ina); + } else { + /*Let the button matrix's styles*/ + } + } + /*Copy an existing keyboard*/ + else { + lv_kb_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->ta = NULL; + ext->ta = copy_ext->ta; + ext->mode = copy_ext->mode; + ext->cursor_mng = copy_ext->cursor_mng; + ext->hide_action = copy_ext->hide_action; + ext->ok_action = copy_ext->ok_action; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_kb); + } + + + LV_LOG_INFO("keyboard created"); + + + return new_kb; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + lv_cursor_type_t cur_type; + + /*Hide the cursor of the old Text area if cursor management is enabled*/ + if(ext->ta && ext->cursor_mng) { + cur_type = lv_ta_get_cursor_type(ext->ta); + lv_ta_set_cursor_type(ext->ta, cur_type | LV_CURSOR_HIDDEN); + } + + ext->ta = ta; + + /*Show the cursor of the new Text area if cursor management is enabled*/ + if(ext->ta && ext->cursor_mng) { + cur_type = lv_ta_get_cursor_type(ext->ta); + lv_ta_set_cursor_type(ext->ta, cur_type & (~LV_CURSOR_HIDDEN)); + } +} + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + if(ext->mode == mode) return; + + ext->mode = mode; + if(mode == LV_KB_MODE_TEXT) lv_btnm_set_map(kb, kb_map_lc); + else if(mode == LV_KB_MODE_NUM) lv_btnm_set_map(kb, kb_map_num); + else if (mode == LV_KB_MODE_HEX) lv_btnm_set_map(kb, kb_map_hex); +} + + +/** + * Automatically hide or show the cursor of Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + if(ext->cursor_mng == en) return; + + ext->cursor_mng = en == false ? 0 : 1; + + if(ext->ta) { + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ext->ta); + + if(ext->cursor_mng) { + lv_ta_set_cursor_type(ext->ta, cur_type & (~LV_CURSOR_HIDDEN)); + } else { + lv_ta_set_cursor_type(ext->ta, cur_type | LV_CURSOR_HIDDEN); + } + } +} + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + ext->ok_action = action; +} + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + ext->hide_action = action; +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t * kb, lv_kb_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_KB_STYLE_BG: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BG, style); + break; + case LV_KB_STYLE_BTN_REL: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_REL, style); + break; + case LV_KB_STYLE_BTN_PR: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_KB_STYLE_BTN_TGL_REL: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_KB_STYLE_BTN_TGL_PR: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_KB_STYLE_BTN_INA: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_INA, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->ta; +} + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->mode; +} + + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->cursor_mng == 0 ? false : true; +} + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->ok_action; +} + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->hide_action; +} + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t * kb, lv_kb_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_KB_STYLE_BG: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BG); + break; + case LV_KB_STYLE_BTN_REL: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_REL); + break; + case LV_KB_STYLE_BTN_PR: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_PR); + break; + case LV_KB_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_KB_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_PR); + break; + case LV_KB_STYLE_BTN_INA: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the keyboard + * @param kb pointer to a keyboard object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(kb, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_kb"; + } + + return res; +} + +/** + * Called when a button of 'kb_btnm' is released + * @param btnm pointer to 'kb_btnm' + * @param i the index of the released button from the current btnm map + * @return LV_ACTION_RES_INV if the btnm is deleted else LV_ACTION_RES_OK + */ +static lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + lv_res_t res = LV_RES_OK; + + /*Do the corresponding action according to the text of the button*/ + if(strcmp(txt, "abc") == 0) { + lv_btnm_set_map(kb, kb_map_lc); + return LV_RES_OK; + } else if(strcmp(txt, "ABC") == 0) { + lv_btnm_set_map(kb, kb_map_uc); + return LV_RES_OK; + } else if(strcmp(txt, "1#") == 0) { + lv_btnm_set_map(kb, kb_map_spec); + return LV_RES_OK; + } else if(strcmp(txt, SYMBOL_CLOSE) == 0) { + if(ext->hide_action) res = ext->hide_action(kb); + else { + lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/ + lv_obj_del(kb); + } + return res; + } else if(strcmp(txt, SYMBOL_OK) == 0) { + if(ext->ok_action) res = ext->ok_action(kb); + else { + lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/ + res = lv_obj_del(kb); + } + return res; + } + + if(res != LV_RES_OK) return res; /*The keyboard might be deleted in the actions*/ + + /*Add the characters to the text area if set*/ + if(ext->ta == NULL) return res; + + if(strcmp(txt, "Enter") == 0)lv_ta_add_char(ext->ta, '\n'); + else if(strcmp(txt, SYMBOL_LEFT) == 0) lv_ta_cursor_left(ext->ta); + else if(strcmp(txt, SYMBOL_RIGHT) == 0) lv_ta_cursor_right(ext->ta); + else if(strcmp(txt, "Bksp") == 0) lv_ta_del_char(ext->ta); + else if(strcmp(txt, "+/-") == 0) { + uint16_t cur = lv_ta_get_cursor_pos(ext->ta); + const char * ta_txt = lv_ta_get_text(ext->ta); + if(ta_txt[0] == '-') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '+'); + lv_ta_set_cursor_pos(ext->ta, cur); + } else if(ta_txt[0] == '+') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur); + } else { + lv_ta_set_cursor_pos(ext->ta, 0); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur + 1); + } + } else { + lv_ta_add_text(ext->ta, txt); + } + return LV_RES_OK; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_kb.h b/bdk/libs/lvgl/lv_objx/lv_kb.h new file mode 100644 index 0000000..027b121 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_kb.h @@ -0,0 +1,216 @@ +/* + * 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 . + */ + +/** + * @file lv_kb.h + * + */ + +#ifndef LV_KB_H +#define LV_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_KB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_TA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btnm.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_KB_MODE_TEXT, + LV_KB_MODE_NUM, + LV_KB_MODE_HEX +}; +typedef uint8_t lv_kb_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnm_ext_t btnm; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *ta; /*Pointer to the assigned text area*/ + lv_kb_mode_t mode; /*Key map type*/ + uint8_t cursor_mng :1; /*1: automatically show/hide cursor when a text area is assigned or left*/ + lv_action_t ok_action; /*Called when the "Ok" button is clicked*/ + lv_action_t hide_action; /*Called when the "Hide" button is clicked*/ +} lv_kb_ext_t; + +enum { + LV_KB_STYLE_BG, + LV_KB_STYLE_BTN_REL, + LV_KB_STYLE_BTN_PR, + LV_KB_STYLE_BTN_TGL_REL, + LV_KB_STYLE_BTN_TGL_PR, + LV_KB_STYLE_BTN_INA, +}; +typedef uint8_t lv_kb_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode); + +/** + * Automatically hide or show the cursor of the current Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en); + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param map pointer to a string array to describe the map. + * See 'lv_btnm_set_map()' for more info. + */ +static inline void lv_kb_set_map(lv_obj_t *kb, const char ** map) +{ + lv_btnm_set_map(kb, map); +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb); + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb); + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_KB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_KB_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_label.c b/bdk/libs/lvgl/lv_objx/lv_label.c new file mode 100644 index 0000000..57ac2d0 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_label.c @@ -0,0 +1,987 @@ +/** + * @file lv_rect.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_label.h" +#if USE_LV_LABEL != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_lang.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +/*Test configurations*/ +#ifndef LV_LABEL_SCROLL_SPEED +#define LV_LABEL_SCROLL_SPEED (25) /*Hor, or ver. scroll speed (px/sec) in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +#define ANIM_WAIT_CHAR_COUNT 3 + +#define LV_LABEL_DOT_END_INV 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param); +static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode); +static void lv_label_refr_text(lv_obj_t * label); +static void lv_label_revert_dots(lv_obj_t * label); + +#if USE_LV_ANIMATION +static void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x); +static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y); +#endif +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("label create started"); + + /*Create a basic object*/ + lv_obj_t * new_label = lv_obj_create(par, copy); + lv_mem_assert(new_label); + if(new_label == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_label); + + /*Extend the basic object to a label object*/ + lv_obj_allocate_ext_attr(new_label, sizeof(lv_label_ext_t)); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(new_label); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->text = NULL; + ext->static_txt = 0; + ext->recolor = 0; + ext->body_draw = 0; + ext->align = LV_LABEL_ALIGN_LEFT; + ext->dot_end = LV_LABEL_DOT_END_INV; + ext->long_mode = LV_LABEL_LONG_EXPAND; + ext->anim_speed = LV_LABEL_SCROLL_SPEED; + ext->offset.x = 0; + ext->offset.y = 0; +#if USE_LV_MULTI_LANG + ext->lang_txt_id = LV_LANG_TXT_ID_NONE; +#endif + lv_obj_set_design_func(new_label, lv_label_design); + lv_obj_set_signal_func(new_label, lv_label_signal); + + /*Init the new label*/ + if(copy == NULL) { + lv_obj_set_click(new_label, false); + lv_label_set_long_mode(new_label, LV_LABEL_LONG_EXPAND); + lv_label_set_text(new_label, "Text"); + lv_label_set_style(new_label, NULL); /*Inherit parent's style*/ + } + /*Copy 'copy' if not NULL*/ + else { + lv_label_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_label_set_long_mode(new_label, lv_label_get_long_mode(copy)); + lv_label_set_recolor(new_label, lv_label_get_recolor(copy)); + lv_label_set_body_draw(new_label, lv_label_get_body_draw(copy)); + lv_label_set_align(new_label, lv_label_get_align(copy)); + if(copy_ext->static_txt == 0) lv_label_set_text(new_label, lv_label_get_text(copy)); + else lv_label_set_static_text(new_label, lv_label_get_text(copy)); + + /*In DOT mode save the text byte-to-byte because a '\0' can be in the middle*/ + if(copy_ext->long_mode == LV_LABEL_LONG_DOT) { + ext->text = lv_mem_realloc(ext->text, lv_mem_get_size(copy_ext->text)); + lv_mem_assert(ext->text); + if(ext->text == NULL) return NULL; + memcpy(ext->text, copy_ext->text, lv_mem_get_size(copy_ext->text)); + } + + memcpy(ext->dot_tmp, copy_ext->dot_tmp, sizeof(ext->dot_tmp)); + ext->dot_end = copy_ext->dot_end; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_label); + } + + + LV_LOG_INFO("label created"); + + return new_label; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text) +{ + lv_obj_invalidate(label); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*If text is NULL then refresh */ + if(text == NULL) { + lv_label_refr_text(label); + return; + } + + if(ext->text == text && ext->static_txt == 0) { + /*If set its own text then reallocate it (maybe its size changed)*/ + ext->text = lv_mem_realloc(ext->text, strlen(ext->text) + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + } else { + /*Allocate space for the new text*/ + uint32_t len = strlen(text) + 1; + if(ext->text != NULL && ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + + ext->text = lv_mem_alloc(len); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + strcpy(ext->text, text); + ext->static_txt = 0; /*Now the text is dynamically allocated*/ + } + + lv_label_refr_text(label); +} + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size) +{ + lv_obj_invalidate(label); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*If trying to set its own text or the array is NULL then refresh */ + if(array == ext->text || array == NULL) { + lv_label_refr_text(label); + return; + } + + /*Allocate space for the new text*/ + if(ext->text != NULL && ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + ext->text = lv_mem_alloc(size + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + memcpy(ext->text, array, size); + ext->text[size] = '\0'; + ext->static_txt = 0; /*Now the text is dynamically allocated*/ + + lv_label_refr_text(label); +} + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->static_txt == 0 && ext->text != NULL) { + lv_mem_free(ext->text); + ext->text = NULL; + } + + if(text != NULL) { + ext->static_txt = 1; + ext->text = (char *) text; + } + + lv_label_refr_text(label); +} + +#if USE_LV_MULTI_LANG +/** + *Set a text ID which refers a the same text but in a different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->lang_txt_id = txt_id; + + /*Apply the new language*/ + label->signal_func(label, LV_SIGNAL_LANG_CHG, NULL); +} +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + +#if USE_LV_ANIMATION + /*Delete the old animation (if exists)*/ + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x); + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y); + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x); + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y); +#endif + ext->offset.x = 0; + ext->offset.y = 0; + + if(long_mode == LV_LABEL_LONG_ROLL || long_mode == LV_LABEL_LONG_CROP) ext->expand = 1; + else ext->expand = 0; + + /*Restore the character under the dots*/ + if(ext->long_mode == LV_LABEL_LONG_DOT && ext->dot_end != LV_LABEL_DOT_END_INV) { + lv_label_revert_dots(label); + } + + ext->long_mode = long_mode; + lv_label_refr_text(label); +} + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t * label, lv_label_align_t align) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->align == align) return; + + ext->align = align; + + lv_obj_invalidate(label); /*Enough to invalidate because alignment is only drawing related (lv_refr_label_text() not required)*/ +} + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->recolor == en) return; + + ext->recolor = en == false ? 0 : 1; + + lv_label_refr_text(label); /*Refresh the text because the potential colo codes in text needs to be hided or revealed*/ +} + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t * label, bool en) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->body_draw == en) return; + + ext->body_draw = en == false ? 0 : 1; + + lv_obj_refresh_ext_size(label); + + lv_obj_invalidate(label); +} + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->anim_speed == anim_speed) return; + + ext->anim_speed = anim_speed; + + if(ext->long_mode == LV_LABEL_LONG_ROLL || ext->long_mode == LV_LABEL_LONG_SCROLL) { + lv_label_refr_text(label); + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + return ext->text; +} + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->lang_txt_id; +} +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->long_mode; +} + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->align; +} + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->recolor == 0 ? false : true; +} + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->body_draw == 0 ? false : true; +} + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->anim_speed; +} + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos) +{ + const char * txt = lv_label_get_text(label); + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + uint8_t letter_height = lv_font_get_height(font); + lv_coord_t y = 0; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + /*If the width will be expanded the set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + index = lv_txt_encoded_get_byte_id(txt, index); + + /*Search the line of the index letter */; + while(txt[new_line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + if(index < new_line_start || txt[new_line_start] == '\0') break; /*The line of 'index' letter begins at 'line_start'*/ + + y += letter_height + style->text.line_space; + line_start = new_line_start; + } + + /*If the last character is line break then go to the next line*/ + if(index > 0) { + if((txt[index - 1] == '\n' || txt[index - 1] == '\r') && txt[index] == '\0') { + y += letter_height + style->text.line_space; + line_start = index; + } + } + + /*Calculate the x coordinate*/ + lv_coord_t x = lv_txt_get_width(&txt[line_start], index - line_start, + font, style->text.letter_space, flag); + + if(index != line_start) x += style->text.letter_space; + + if(ext->align == LV_LABEL_ALIGN_CENTER) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + x += lv_obj_get_width(label) / 2 - line_w / 2; + + } else if(ext->align == LV_LABEL_ALIGN_RIGHT) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + + x += lv_obj_get_width(label) - line_w; + } + pos->x = x; + pos->y = y; +} + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) +{ + const char * txt = lv_label_get_text(label); + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + uint8_t letter_height = lv_font_get_height(font); + lv_coord_t y = 0; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + /*If the width will be expanded set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + /*Search the line of the index letter */; + while(txt[line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + + if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/ + y += letter_height + style->text.line_space; + + line_start = new_line_start; + } + + /*Calculate the x coordinate*/ + lv_coord_t x = 0; + if(ext->align == LV_LABEL_ALIGN_CENTER) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + x += lv_obj_get_width(label) / 2 - line_w / 2; + } + + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t i = line_start; + uint32_t i_current = i; + uint32_t letter; + while(i < new_line_start - 1) { + letter = lv_txt_encoded_next(txt, &i); /*Be careful 'i' already points to the next character*/ + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + x += lv_font_get_width(font, letter); + if(pos->x < x) { + i = i_current; + break; + } + x += style->text.letter_space; + i_current = i; + } + + return lv_encoded_get_char_id(txt, i); +} + + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*Can not append to static text*/ + if(ext->static_txt != 0) return; + + lv_obj_invalidate(label); + + /*Allocate space for the new text*/ + uint32_t old_len = strlen(ext->text); + uint32_t ins_len = strlen(txt); + uint32_t new_len = ins_len + old_len; + ext->text = lv_mem_realloc(ext->text, new_len + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + if(pos == LV_LABEL_POS_LAST) { +#if LV_TXT_UTF8 == 0 + pos = old_len; +#else + pos = lv_txt_get_encoded_length(ext->text); +#endif + } + + lv_txt_ins(ext->text, pos, txt); + + lv_label_refr_text(label); +} + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*Can not append to static text*/ + if(ext->static_txt != 0) return; + + lv_obj_invalidate(label); + + char * label_txt = lv_label_get_text(label); + /*Delete the characters*/ + lv_txt_cut(label_txt, pos, cnt); + + /*Refresh the label*/ + lv_label_refr_text(label); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the labels + * @param label pointer to a label object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode) +{ + /* A label never covers an area */ + if(mode == LV_DESIGN_COVER_CHK) return false; + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_area_t coords; + lv_style_t * style = lv_obj_get_style(label); + lv_opa_t opa_scale = lv_obj_get_opa_scale(label); + lv_obj_get_coords(label, &coords); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(label); + if(lv_group_get_focused(g) == label) { + lv_draw_rect(&coords, mask, style, opa_scale); + } +#endif + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + if(ext->body_draw) { + lv_area_t bg; + lv_obj_get_coords(label, &bg); + bg.x1 -= style->body.padding.hor; + bg.x2 += style->body.padding.hor; + bg.y1 -= style->body.padding.ver; + bg.y2 += style->body.padding.ver; + + lv_draw_rect(&bg, mask, style, lv_obj_get_opa_scale(label)); + } + + /*TEST: draw a background for the label*/ + //lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER); + + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(ext->align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; + + /* In ROLL mode the CENTER and RIGHT are pointless so remove them. + * (In addition they will result mis-alignment is this case)*/ + if((ext->long_mode == LV_LABEL_LONG_ROLL) && + (ext->align == LV_LABEL_ALIGN_CENTER || ext->align == LV_LABEL_ALIGN_RIGHT)) { + lv_point_t size; + lv_txt_get_size(&size, ext->text, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); + if(size.x > lv_obj_get_width(label)) { + flag &= ~LV_TXT_FLAG_RIGHT; + flag &= ~LV_TXT_FLAG_CENTER; + } + } + + lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset); + } + return true; +} + + + +/** + * Signal function of the label + * @param label pointer to a label object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(label, sign, param); + if(res != LV_RES_OK) return res; + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Revert dots for proper refresh*/ + lv_label_revert_dots(label); + + lv_label_refr_text(label); + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_area_get_width(&label->coords) != lv_area_get_width(param) || + lv_area_get_height(&label->coords) != lv_area_get_height(param)) { + lv_label_revert_dots(label); + lv_label_refr_text(label); + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + if(ext->body_draw) { + lv_style_t * style = lv_label_get_style(label); + label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.hor); + label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.ver); + } + } else if(sign == LV_SIGNAL_LANG_CHG) { +#if USE_LV_MULTI_LANG + if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) { + const char * lang_txt = lv_lang_get_text(ext->lang_txt_id); + if(lang_txt) { + lv_label_set_text(label, lang_txt); + } else { + LV_LOG_WARN("lv_lang_get_text return NULL for a label's text"); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_label"; + } + + return res; +} + +/** + * Refresh the label with its text stored in its extended data + * @param label pointer to a label object + */ +static void lv_label_refr_text(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + if(ext->text == NULL) return; + + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + + /*If the width will be expanded set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || + ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + /*Calc. the height and longest line*/ + lv_point_t size; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + lv_txt_get_size(&size, ext->text, font, style->text.letter_space, style->text.line_space, max_w, flag); + + /*Set the full size in expand mode*/ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + lv_obj_set_size(label, size.x, size.y); + + /*Start scrolling if the label is greater then its parent*/ + if(ext->long_mode == LV_LABEL_LONG_SCROLL) { +#if USE_LV_ANIMATION + lv_obj_t * parent = lv_obj_get_parent(label); + + /*Delete the potential previous scroller animations*/ + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x); + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y); + + lv_anim_t anim; + anim.var = label; + anim.repeat = 1; + anim.playback = 1; + anim.start = 0; + anim.act_time = 0; + anim.end_cb = NULL; + anim.path = lv_anim_path_linear; + + anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') + + style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT; + anim.repeat_pause = anim.playback_pause; + + if(lv_obj_get_width(label) > lv_obj_get_width(parent)) { + anim.end = lv_obj_get_width(parent) - lv_obj_get_width(label); + anim.fp = (lv_anim_fp_t) lv_obj_set_x; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } else if(lv_obj_get_height(label) > lv_obj_get_height(parent)) { + anim.end = lv_obj_get_height(parent) - lv_obj_get_height(label) - lv_font_get_height(font); + anim.fp = (lv_anim_fp_t)lv_obj_set_y; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } +#endif + } + } + /*In roll mode keep the size but start offset animations*/ + else if(ext->long_mode == LV_LABEL_LONG_ROLL) { +#if USE_LV_ANIMATION + lv_anim_t anim; + anim.var = label; + anim.repeat = 1; + anim.playback = 1; + anim.start = 0; + anim.act_time = 0; + anim.end_cb = NULL; + anim.path = lv_anim_path_linear; + anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') + style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT; + anim.repeat_pause = anim.playback_pause; + + bool hor_anim = false; + if(size.x > lv_obj_get_width(label)) { + anim.end = lv_obj_get_width(label) - size.x; + anim.fp = (lv_anim_fp_t) lv_label_set_offset_x; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + hor_anim = true; + } else { + /*Delete the offset animation if not required*/ + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x); + ext->offset.x = 0; + } + + if(size.y > lv_obj_get_height(label) && hor_anim == false) { + anim.end = lv_obj_get_height(label) - size.y - (lv_font_get_height(font)); + anim.fp = (lv_anim_fp_t)lv_label_set_offset_y; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } else { + /*Delete the offset animation if not required*/ + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y); + ext->offset.y = 0; + } +#endif + } else if(ext->long_mode == LV_LABEL_LONG_DOT) { + if(size.y <= lv_obj_get_height(label)) { /*No dots are required, the text is short enough*/ + ext->dot_end = LV_LABEL_DOT_END_INV; + } else if(lv_txt_get_encoded_length(ext->text) <= LV_LABEL_DOT_NUM) { /*Don't turn to dots all the characters*/ + ext->dot_end = LV_LABEL_DOT_END_INV; + } else { + lv_point_t p; + p.x = lv_obj_get_width(label) - (lv_font_get_width(style->text.font, '.') + style->text.letter_space) * LV_LABEL_DOT_NUM; /*Shrink with dots*/ + p.y = lv_obj_get_height(label); + p.y -= p.y % (lv_font_get_height(style->text.font) + style->text.line_space); /*Round down to the last line*/ + p.y -= style->text.line_space; /*Trim the last line space*/ + uint32_t letter_id = lv_label_get_letter_on(label, &p); + + +#if LV_TXT_UTF8 == 0 + /*Save letters under the dots and replace them with dots*/ + uint8_t i; + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->dot_tmp[i] = ext->text[letter_id + i]; + ext->text[letter_id + i] = '.'; + } + + ext->dot_tmp[LV_LABEL_DOT_NUM] = ext->text[letter_id + LV_LABEL_DOT_NUM]; + ext->text[letter_id + LV_LABEL_DOT_NUM] = '\0'; + + ext->dot_end = letter_id + LV_LABEL_DOT_NUM; +#else + /*Save letters under the dots and replace them with dots*/ + uint32_t i; + uint32_t byte_id = lv_txt_encoded_get_byte_id(ext->text, letter_id); + uint32_t byte_id_ori = byte_id; + uint8_t len = 0; + for(i = 0; i <= LV_LABEL_DOT_NUM; i++) { + len += lv_txt_encoded_size(&ext->text[byte_id]); + lv_txt_encoded_next(ext->text, &byte_id); + } + + memcpy(ext->dot_tmp, &ext->text[byte_id_ori], len); + ext->dot_tmp[len] = '\0'; /*Close with a zero*/ + + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->text[byte_id_ori + i] = '.'; + } + ext->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0'; + + ext->dot_end = letter_id + LV_LABEL_DOT_NUM; +#endif + + } + } + /*In break mode only the height can change*/ + else if(ext->long_mode == LV_LABEL_LONG_BREAK) { + lv_obj_set_height(label, size.y); + } + /*Do not set the size in Clip mode*/ + else if(ext->long_mode == LV_LABEL_LONG_CROP) { + /*Do nothing*/ + } + + + lv_obj_invalidate(label); +} + +static void lv_label_revert_dots(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->long_mode != LV_LABEL_LONG_DOT) return; + if(ext->dot_end == LV_LABEL_DOT_END_INV) return; +#if LV_TXT_UTF8 == 0 + uint32_t i; + for(i = 0; i <= LV_LABEL_DOT_NUM; i++) { + ext->text[ext->dot_end - i] = ext->dot_tmp[LV_LABEL_DOT_NUM - i]; + } +#else + uint32_t letter_i = ext->dot_end - LV_LABEL_DOT_NUM; + uint32_t byte_i = lv_txt_encoded_get_byte_id(ext->text, letter_i); + + /*Restore the characters*/ + uint8_t i = 0; + while(ext->dot_tmp[i] != '\0') { + ext->text[byte_i + i] = ext->dot_tmp[i]; + i++; + } +#endif + + ext->dot_end = LV_LABEL_DOT_END_INV; +} + +#if USE_LV_ANIMATION +static void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->offset.x = x; + lv_obj_invalidate(label); +} + +static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->offset.y = y; + lv_obj_invalidate(label); +} +#endif +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_label.h b/bdk/libs/lvgl/lv_objx/lv_label.h new file mode 100644 index 0000000..a2ee126 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_label.h @@ -0,0 +1,295 @@ +/** + * @file lv_rect.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LABEL != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/*Long mode behaviors. Used in 'lv_label_ext_t' */ +enum +{ + LV_LABEL_LONG_EXPAND, /*Expand the object size to the text size*/ + LV_LABEL_LONG_BREAK, /*Keep the object width, break the too long lines and expand the object height*/ + LV_LABEL_LONG_SCROLL, /*Expand the object size and scroll the text on the parent (move the label object)*/ + LV_LABEL_LONG_DOT, /*Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_ROLL, /*Keep the size and roll the text infinitely*/ + LV_LABEL_LONG_CROP, /*Keep the size and crop the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +/*Label align policy*/ +enum { + LV_LABEL_ALIGN_LEFT, + LV_LABEL_ALIGN_CENTER, + LV_LABEL_ALIGN_RIGHT, +}; +typedef uint8_t lv_label_align_t; + +/*Data of label*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + char * text; /*Text of the label*/ + lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/ +#if LV_TXT_UTF8 == 0 + char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#else + char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#endif + +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the text to display*/ +#endif + uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ + uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/ + lv_point_t offset; /*Text draw position offset*/ + uint8_t static_txt :1; /*Flag to indicate the text is static*/ + uint8_t align :2; /*Align type from 'lv_label_align_t'*/ + uint8_t recolor :1; /*Enable in-line letter re-coloring*/ + uint8_t expand :1; /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/ + uint8_t body_draw :1; /*Draw background body*/ +} lv_label_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text); + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text); + +/** + *Set a text ID which means a the same text but on different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +#if USE_LV_MULTI_LANG +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id); +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t *label, lv_label_align_t align); + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en); + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t *label, bool en); + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed); + +/** + * Set the style of an label + * @param label pointer to an label object + * @param style pointer to a style + */ +static inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style) +{ + lv_obj_set_style(label, style); +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label); + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label); +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label); + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label); + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label); + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t *label); + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t *label); + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); + +/** + * Get the style of an label object + * @param label pointer to an label object + * @return pointer to the label's style + */ +static inline lv_style_t* lv_label_get_style(const lv_obj_t *label) +{ + return lv_obj_get_style(label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LABEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_led.c b/bdk/libs/lvgl/lv_objx/lv_led.c new file mode 100644 index 0000000..29fc967 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_led.c @@ -0,0 +1,244 @@ +/** + * @file lv_led.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_led.h" +#if USE_LV_LED != 0 + +#include "../lv_themes/lv_theme.h" +#include "../lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ +#define LV_LED_WIDTH_DEF (LV_DPI / 3) +#define LV_LED_HEIGHT_DEF (LV_DPI / 3) +#define LV_LED_BRIGHT_OFF 100 +#define LV_LED_BRIGHT_ON 255 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("led create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_led = lv_obj_create(par, copy); + lv_mem_assert(new_led); + if(new_led == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_led); + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_led); + + /*Allocate the object type specific extended data*/ + lv_led_ext_t * ext = lv_obj_allocate_ext_attr(new_led, sizeof(lv_led_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->bright = LV_LED_BRIGHT_ON; + + lv_obj_set_signal_func(new_led, lv_led_signal); + lv_obj_set_design_func(new_led, lv_led_design); + + /*Init the new led object*/ + if(copy == NULL) { + lv_obj_set_size(new_led, LV_LED_WIDTH_DEF, LV_LED_HEIGHT_DEF); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_led_set_style(new_led, th->led); + } else { + lv_led_set_style(new_led, &lv_style_pretty_color); + } + } + /*Copy an existing object*/ + else { + lv_led_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->bright = copy_ext->bright; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_led); + } + + + LV_LOG_INFO("led created"); + + return new_led; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright) +{ + /*Set the brightness*/ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + if(ext->bright == bright) return; + + ext->bright = bright; + + /*Invalidate the object there fore it will be redrawn*/ + lv_obj_invalidate(led); +} + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led) +{ + lv_led_set_bright(led, LV_LED_BRIGHT_ON); +} + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led) +{ + lv_led_set_bright(led, LV_LED_BRIGHT_OFF); +} + + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led) +{ + uint8_t bright = lv_led_get_bright(led); + if(bright > (LV_LED_BRIGHT_OFF + LV_LED_BRIGHT_ON) >> 1) lv_led_off(led); + else lv_led_on(led); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led) +{ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + return ext->bright; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the leds + * @param led pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask area*/ + return ancestor_design_f(led, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Make darker colors in a temporary style according to the brightness*/ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + lv_style_t * style = lv_obj_get_style(led); + + /* Store the real pointer because of 'lv_group' + * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style + * and to the real object style. It is important because of style change tricks below*/ + lv_style_t * style_ori_p = led->style_p; + + /*Create a temporal style*/ + lv_style_t leds_tmp; + memcpy(&leds_tmp, style, sizeof(leds_tmp)); + + /*Mix. the color with black proportionally with brightness*/ + leds_tmp.body.main_color = lv_color_mix(leds_tmp.body.main_color, LV_COLOR_BLACK, ext->bright); + leds_tmp.body.grad_color = lv_color_mix(leds_tmp.body.grad_color, LV_COLOR_BLACK, ext->bright); + leds_tmp.body.border.color = lv_color_mix(leds_tmp.body.border.color, LV_COLOR_BLACK, ext->bright); + + /*Set the current swidth according to brightness proportionally between LV_LED_BRIGHT_OFF and LV_LED_BRIGHT_ON*/ + uint16_t bright_tmp = ext->bright; + leds_tmp.body.shadow.width = ((bright_tmp - LV_LED_BRIGHT_OFF) * style->body.shadow.width) / (LV_LED_BRIGHT_ON - LV_LED_BRIGHT_OFF); + + led->style_p = &leds_tmp; + ancestor_design_f(led, mask, mode); + led->style_p = style_ori_p; /*Restore the ORIGINAL style pointer*/ + } + return true; +} + +/** + * Signal function of the led + * @param led pointer to a led object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(led, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_led"; + } + + return res; +} +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_led.h b/bdk/libs/lvgl/lv_objx/lv_led.h new file mode 100644 index 0000000..25e48a7 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_led.h @@ -0,0 +1,116 @@ +/** + * @file lv_led.h + * + */ + +#ifndef LV_LED_H +#define LV_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LED != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct +{ + /*No inherited ext.*/ + /*New data for this type */ + uint8_t bright; /*Current brightness of the LED (0..255)*/ +} lv_led_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright); + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led); + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led); + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led); + +/** + * Set the style of a led + * @param led pointer to a led object + * @param style pointer to a style + */ +static inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style) +{ + lv_obj_set_style(led, style); +} + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led); + +/** + * Get the style of an led object + * @param led pointer to an led object + * @return pointer to the led's style + */ +static inline lv_style_t* lv_led_get_style(const lv_obj_t *led) +{ + return lv_obj_get_style(led); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LED*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LED_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_line.c b/bdk/libs/lvgl/lv_objx/lv_line.c new file mode 100644 index 0000000..0e16337 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_line.c @@ -0,0 +1,301 @@ +/** + * @file lv_line.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_line.h" + +#if USE_LV_LINE != 0 +#include "../lv_draw/lv_draw.h" +#include "../lv_misc/lv_math.h" +#include +#include + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("line create started"); + + /*Create a basic object*/ + lv_obj_t * new_line = lv_obj_create(par, copy); + lv_mem_assert(new_line); + if(new_line == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_line); + + /*Extend the basic object to line object*/ + lv_line_ext_t * ext = lv_obj_allocate_ext_attr(new_line, sizeof(lv_line_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->point_num = 0; + ext->point_array = NULL; + ext->auto_size = 1; + ext->y_inv = 0; + + lv_obj_set_design_func(new_line, lv_line_design); + lv_obj_set_signal_func(new_line, lv_line_signal); + + /*Init the new line*/ + if(copy == NULL) { + lv_obj_set_size(new_line, LV_DPI, LV_DPI); /*Auto size is enables, but set default size until no points are added*/ + lv_obj_set_style(new_line, NULL); /*Inherit parent's style*/ + lv_obj_set_click(new_line, false); + } + /*Copy an existing object*/ + else { + lv_line_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy)); + lv_line_set_y_invert(new_line, lv_line_get_y_invert(copy)); + lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy)); + lv_line_set_points(new_line, copy_ext->point_array, copy_ext->point_num); + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_line); + } + + + LV_LOG_INFO("line created"); + + return new_line; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + ext->point_array = point_a; + ext->point_num = point_num; + + if(point_num > 0 && ext->auto_size != 0) { + uint16_t i; + lv_coord_t xmax = LV_COORD_MIN; + lv_coord_t ymax = LV_COORD_MIN; + for(i = 0; i < point_num; i++) { + xmax = LV_MATH_MAX(point_a[i].x, xmax); + ymax = LV_MATH_MAX(point_a[i].y, ymax); + } + + lv_style_t * style = lv_line_get_style(line); + lv_obj_set_size(line, xmax + style->line.width, ymax + style->line.width); + } + + lv_obj_invalidate(line); +} + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + if(ext->auto_size == en) return; + + ext->auto_size = en == false ? 0 : 1; + + /*Refresh the object*/ + if(en) lv_line_set_points(line, ext->point_array, ext->point_num); +} + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + if(ext->y_inv == en) return; + + ext->y_inv = en == false ? 0 : 1; + + lv_obj_invalidate(line); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + return ext->auto_size == 0 ? false : true; +} + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + return ext->y_inv == 0 ? false : true; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the lines + * @param line pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*A line never covers an area*/ + if(mode == LV_DESIGN_COVER_CHK) return false; + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + if(ext->point_num == 0 || ext->point_array == NULL) return false; + + lv_style_t * style = lv_obj_get_style(line); + lv_opa_t opa_scale = lv_obj_get_opa_scale(line); + lv_area_t area; + lv_obj_get_coords(line, &area); + lv_coord_t x_ofs = area.x1; + lv_coord_t y_ofs = area.y1; + lv_point_t p1; + lv_point_t p2; + lv_coord_t h = lv_obj_get_height(line); + uint16_t i; + + lv_style_t circle_style; /*If rounded...*/ + lv_style_copy(&circle_style, style); + circle_style.body.radius = LV_RADIUS_CIRCLE; + circle_style.body.main_color = style->line.color; + circle_style.body.grad_color = style->line.color; + circle_style.body.opa = style->line.opa; + lv_area_t circle_area; + + /*Read all points and draw the lines*/ + for(i = 0; i < ext->point_num - 1; i++) { + + p1.x = ext->point_array[i].x + x_ofs; + p2.x = ext->point_array[i + 1].x + x_ofs; + + if(ext->y_inv == 0) { + p1.y = ext->point_array[i].y + y_ofs; + p2.y = ext->point_array[i + 1].y + y_ofs; + } else { + p1.y = h - ext->point_array[i].y + y_ofs; + p2.y = h - ext->point_array[i + 1].y + y_ofs; + } + lv_draw_line(&p1, &p2, mask, style, opa_scale); + + /*Draw circle on the joints if enabled*/ + if(style->line.rounded) { + circle_area.x1 = p1.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.y1 = p1.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.x2 = p1.x + ((style->line.width - 1) >> 1); + circle_area.y2 = p1.y + ((style->line.width - 1) >> 1); + lv_draw_rect(&circle_area, mask, &circle_style, opa_scale); + } + } + + /*Draw circle on the last point too if enabled*/ + if(style->line.rounded) { + circle_area.x1 = p2.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.y1 = p2.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.x2 = p2.x + ((style->line.width - 1) >> 1); + circle_area.y2 = p2.y + ((style->line.width - 1) >> 1); + lv_draw_rect(&circle_area, mask, &circle_style, opa_scale); + } + } + return true; +} + +/** + * Signal function of the line + * @param line pointer to a line object + * @param sign a signal type from lv_signal_t enum + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(line, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_line"; + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_line_get_style(line); + if(line->ext_size < style->line.width) line->ext_size = style->line.width; + } + + + return res; +} +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_line.h b/bdk/libs/lvgl/lv_objx/lv_line.h new file mode 100644 index 0000000..377d399 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_line.h @@ -0,0 +1,158 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LINE != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + const lv_point_t * point_array; /*Pointer to an array with the points of the line*/ + uint16_t point_num; /*Number of points in 'point_array' */ + uint8_t auto_size :1; /*1: set obj. width to x max and obj. height to y max */ + uint8_t y_inv :1; /*1: y == 0 will be on the bottom*/ +} lv_line_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num); + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en); + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en); + +#define lv_line_set_y_inv lv_line_set_y_invert /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */ + +/** + * Set the style of a line + * @param line pointer to a line object + * @param style pointer to a style + */ +static inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style) +{ + lv_obj_set_style(line, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @param upscale - + */ +static inline void lv_line_set_upscale(lv_obj_t * line, bool upcale) +{ + (void) line; + (void) upcale; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line); + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line); + +/** + * Get the style of an line object + * @param line pointer to an line object + * @return pointer to the line's style + */ +static inline lv_style_t* lv_line_get_style(const lv_obj_t *line) +{ + return lv_obj_get_style(line); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @return false + */ +static inline bool lv_line_get_upscale(const lv_obj_t * line) +{ + (void) line; + return false; +} + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LINE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LINE_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_list.c b/bdk/libs/lvgl/lv_objx/lv_list.c new file mode 100644 index 0000000..b01172f --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_list.c @@ -0,0 +1,1052 @@ +/* + * 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 . + */ + +/** + * @file lv_list.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_list.h" +#if USE_LV_LIST != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_LIST_LAYOUT_DEF LV_LAYOUT_COL_M + +#if USE_LV_ANIMATION +# ifndef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 100 /*Animation time of focusing to the a list element [ms] (0: no animation) */ +# endif +#else +# undef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param); +static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param); +static void refr_btn_width(lv_obj_t * list); +static void lv_list_btn_single_selected(lv_obj_t *btn); +static bool lv_list_is_list_btn(lv_obj_t * list_btn); +static bool lv_list_is_list_img(lv_obj_t * list_btn); +static bool lv_list_is_list_label(lv_obj_t * list_btn); + +/********************** + * STATIC VARIABLES + **********************/ +#if USE_LV_IMG +static lv_signal_func_t img_signal; +#endif +static lv_signal_func_t label_signal; +static lv_signal_func_t ancestor_page_signal; +static lv_signal_func_t ancestor_btn_signal; +#if USE_LV_GROUP +/*Used to make the last clicked button pressed (selected) when the list become focused and `click_focus == 1`*/ +static lv_obj_t * last_clicked_btn; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("list create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_list = lv_page_create(par, copy); + lv_mem_assert(new_list); + if(new_list == NULL) return NULL; + + if(ancestor_page_signal == NULL) ancestor_page_signal = lv_obj_get_signal_func(new_list); + + lv_list_ext_t * ext = lv_obj_allocate_ext_attr(new_list, sizeof(lv_list_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + // Important! + static lv_style_t img_btn_color; + lv_style_copy( &img_btn_color, &lv_style_plain); + img_btn_color.image.color = LV_COLOR_HEX(0xDDDDDD); + img_btn_color.image.intense = LV_OPA_50; + ext->style_img = &img_btn_color; + ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; + ext->anim_time = LV_LIST_FOCUS_TIME; + ext->single_mode = false; + ext->size = 0; + +#if USE_LV_GROUP + ext->last_sel = NULL; + ext->selected_btn = NULL; +#endif + + lv_obj_set_signal_func(new_list, lv_list_signal); + + /*Init the new list object*/ + if(copy == NULL) { + lv_obj_set_size(new_list, 2 * LV_DPI, 3 * LV_DPI); + lv_page_set_scrl_layout(new_list, LV_LIST_LAYOUT_DEF); + lv_list_set_sb_mode(new_list, LV_SB_MODE_DRAG); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_list_set_style(new_list, LV_LIST_STYLE_BG, th->list.bg); + lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, th->list.scrl); + lv_list_set_style(new_list, LV_LIST_STYLE_SB, th->list.sb); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, th->list.btn.rel); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, th->list.btn.pr); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, th->list.btn.tgl_rel); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, th->list.btn.tgl_pr); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, th->list.btn.ina); + } else { + lv_list_set_style(new_list, LV_LIST_STYLE_BG, &lv_style_transp_fit); + lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, &lv_style_pretty); + } + } else { + lv_list_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + lv_obj_t * copy_btn = lv_list_get_next_btn(copy, NULL); + while(copy_btn) { + const void * img_src = NULL; +#if USE_LV_IMG + lv_obj_t * copy_img = lv_list_get_btn_img(copy_btn); + if(copy_img) img_src = lv_img_get_src(copy_img); +#endif + lv_list_add(new_list, img_src, lv_list_get_btn_text(copy_btn), lv_btn_get_action(copy_btn, LV_BTN_ACTION_CLICK)); + copy_btn = lv_list_get_next_btn(copy, copy_btn); + } + + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, copy_ext->styles_btn[LV_BTN_STATE_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, copy_ext->styles_btn[LV_BTN_STATE_PR]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, copy_ext->styles_btn[LV_BTN_STATE_INA]); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_list); + } + + + LV_LOG_INFO("list created"); + + + return new_list; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); + lv_list_ext_t * ext = lv_obj_get_ext_attr(obj); + ext->size = 0; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action) +{ + lv_style_t * style = lv_obj_get_style(list); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->size ++; + /*Create a list element with the image an the text*/ + lv_obj_t * liste; + liste = lv_btn_create(list, NULL); + + /*Save the original signal function because it will be required in `lv_list_btn_signal`*/ + if(ancestor_btn_signal == NULL) ancestor_btn_signal = lv_obj_get_signal_func(liste); + + /*Set the default styles*/ + lv_btn_set_style(liste, LV_BTN_STYLE_REL, ext->styles_btn[LV_BTN_STATE_REL]); + lv_btn_set_style(liste, LV_BTN_STYLE_PR, ext->styles_btn[LV_BTN_STATE_PR]); + lv_btn_set_style(liste, LV_BTN_STYLE_TGL_REL, ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_btn_set_style(liste, LV_BTN_STYLE_TGL_PR, ext->styles_btn[LV_BTN_STATE_TGL_PR]); + lv_btn_set_style(liste, LV_BTN_STYLE_INA, ext->styles_btn[LV_BTN_STATE_INA]); + + lv_btn_set_action(liste, LV_BTN_ACTION_CLICK, rel_action); + lv_page_glue_obj(liste, true); + lv_btn_set_layout(liste, LV_LAYOUT_ROW_M); + lv_btn_set_fit(liste, false, true); + lv_obj_set_protect(liste, LV_PROTECT_PRESS_LOST); + lv_obj_set_signal_func(liste, lv_list_btn_signal); + + /*Make the size adjustment*/ + lv_coord_t w = lv_obj_get_width(list); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(list)); + lv_coord_t pad_hor_tot = style->body.padding.hor + style_scrl->body.padding.hor; + w -= pad_hor_tot * 2; + + lv_obj_set_width(liste, w); +#if USE_LV_IMG != 0 + lv_obj_t * img = NULL; + if(img_src) { + img = lv_img_create(liste, NULL); + lv_img_set_src(img, img_src); + lv_obj_set_style(img, ext->style_img); + lv_obj_set_click(img, false); + if(img_signal == NULL) img_signal = lv_obj_get_signal_func(img); + } +#endif + if(txt != NULL) { + lv_coord_t btn_hor_pad = ext->styles_btn[LV_BTN_STYLE_REL]->body.padding.hor; + lv_obj_t * label = lv_label_create(liste, NULL); + lv_label_set_text(label, txt); + lv_obj_set_click(label, false); + lv_label_set_long_mode(label, LV_LABEL_LONG_ROLL); + lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad); + if(label_signal == NULL) label_signal = lv_obj_get_signal_func(label); + } +#if USE_LV_GROUP + /* If this is the first item to be added to the list and the list is + * focussed, select it */ + { + lv_group_t *g = lv_obj_get_group(list); + if(ext->size == 1 && lv_group_get_focused(g) == list) { + lv_list_set_btn_selected(list, liste); + } + } +#endif + + return liste; +} + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(index >= ext->size) return false; + uint32_t count = 0; + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + while(e != NULL) { + if(count == index) { + lv_obj_del(e); + ext->size --; + return true; + } + e = lv_list_get_next_btn(list, e); + count ++; + } + return false; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + ext->single_mode = mode; +} + +#if USE_LV_GROUP + +/** + * Make a button selected + * @param list pointer to a list object + * @param btn pointer to a button to selectthe + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + if(ext->selected_btn) { + lv_btn_state_t s = lv_btn_get_state(ext->selected_btn); + if(s == LV_BTN_STATE_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_REL); + else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_REL); + } + + ext->selected_btn = btn; + if( btn != NULL ) { + ext->last_sel = btn; + } + + if(ext->selected_btn) { + lv_btn_state_t s = lv_btn_get_state(ext->selected_btn); + if(s == LV_BTN_STATE_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_PR); + else if(s == LV_BTN_STATE_TGL_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_PR); + + lv_page_focus(list, ext->selected_btn, ext->anim_time); + } +} + +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t * list, uint16_t anim_time) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + if(ext->anim_time == anim_time) return; + ext->anim_time = anim_time; +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, lv_style_t * style) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + lv_btn_style_t btn_style_refr = LV_BTN_STYLE_REL; + lv_obj_t * btn; + + switch(type) { + case LV_LIST_STYLE_BG: + lv_page_set_style(list, LV_PAGE_STYLE_BG, style); + /*style change signal will call 'refr_btn_width' */ + break; + case LV_LIST_STYLE_SCRL: + lv_page_set_style(list, LV_PAGE_STYLE_SCRL, style); + refr_btn_width(list); + break; + case LV_LIST_STYLE_SB: + lv_page_set_style(list, LV_PAGE_STYLE_SB, style); + break; + case LV_LIST_STYLE_EDGE_FLASH: + lv_page_set_style(list, LV_PAGE_STYLE_EDGE_FLASH, style); + break; + case LV_LIST_STYLE_BTN_REL: + ext->styles_btn[LV_BTN_STATE_REL] = style; + btn_style_refr = LV_BTN_STYLE_REL; + break; + case LV_LIST_STYLE_BTN_PR: + ext->styles_btn[LV_BTN_STATE_PR] = style; + btn_style_refr = LV_BTN_STYLE_PR; + break; + case LV_LIST_STYLE_BTN_TGL_REL: + ext->styles_btn[LV_BTN_STATE_TGL_REL] = style; + btn_style_refr = LV_BTN_STYLE_TGL_REL; + break; + case LV_LIST_STYLE_BTN_TGL_PR: + ext->styles_btn[LV_BTN_STATE_TGL_PR] = style; + btn_style_refr = LV_BTN_STYLE_TGL_PR; + break; + case LV_LIST_STYLE_BTN_INA: + ext->styles_btn[LV_BTN_STATE_INA] = style; + btn_style_refr = LV_BTN_STYLE_INA; + break; + } + + + /*Refresh existing buttons' style*/ + if(type == LV_LIST_STYLE_BTN_PR || type == LV_LIST_STYLE_BTN_REL || + type == LV_LIST_STYLE_BTN_TGL_REL || type == LV_LIST_STYLE_BTN_TGL_PR || + type == LV_LIST_STYLE_BTN_INA) { + btn = lv_list_get_prev_btn(list, NULL); + while(btn != NULL) { + lv_btn_set_style(btn, btn_style_refr, ext->styles_btn[btn_style_refr]); + btn = lv_list_get_prev_btn(list, btn); + } + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + return (ext->single_mode); +} + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn) +{ + lv_obj_t * label = lv_list_get_btn_label(btn); + if(label == NULL) return ""; + return lv_label_get_text(label); +} + +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn) +{ + lv_obj_t * label = lv_obj_get_child(btn, NULL); + if(label == NULL) return NULL; + + while(lv_list_is_list_label(label) == false) { + label = lv_obj_get_child(btn, label); + if(label == NULL) break; + } + + return label; +} + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn) +{ +#if USE_LV_IMG != 0 + lv_obj_t * img = lv_obj_get_child(btn, NULL); + if(img == NULL) return NULL; + + while(lv_list_is_list_img(img) == false) { + img = lv_obj_get_child(btn, img); + if(img == NULL) break; + } + + return img; +#else + return NULL; +#endif +} + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn) +{ + /* Not a good practice but user can add/create objects to the lists manually. + * When getting the next button try to be sure that it is at least a button */ + + lv_obj_t * btn ; + lv_obj_t * scrl = lv_page_get_scrl(list); + + btn = lv_obj_get_child(scrl, prev_btn); + if(btn == NULL) return NULL; + + while(lv_list_is_list_btn(btn) == false) { + btn = lv_obj_get_child(scrl, btn); + if(btn == NULL) break; + } + + return btn; +} + + + + /** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn) +{ + /* Not a good practice but user can add/create objects to the lists manually. + * When getting the next button try to be sure that it is at least a button */ + + lv_obj_t * btn ; + lv_obj_t * scrl = lv_page_get_scrl(list); + + btn = lv_obj_get_child_back(scrl, prev_btn); + if(btn == NULL) return NULL; + + while(lv_list_is_list_btn(btn) == false) { + btn = lv_obj_get_child_back(scrl, btn); + if(btn == NULL) break; + } + + return btn; +} + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn) +{ + int index = 0; + if( list == NULL ){ + /* no list provided, assuming btn is part of a list */ + list = lv_obj_get_parent(lv_obj_get_parent(btn)); + } + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + while(e != NULL) { + if(e == btn) { + return index; + } + index ++; + e = lv_list_get_next_btn(list, e); + } + return -1; +} + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->size; +} + +#if USE_LV_GROUP +/** + * Get the currently selected button + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->selected_btn; +} + +#endif + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->anim_time; +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type) +{ + lv_style_t * style = NULL; + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + switch(type) { + case LV_LIST_STYLE_BG: + style = lv_page_get_style(list, LV_PAGE_STYLE_BG); + break; + case LV_LIST_STYLE_SCRL: + style = lv_page_get_style(list, LV_PAGE_STYLE_SB); + break; + case LV_LIST_STYLE_SB: + style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); + break; + case LV_LIST_STYLE_EDGE_FLASH: + style = lv_page_get_style(list, LV_PAGE_STYLE_EDGE_FLASH); + break; + case LV_LIST_STYLE_BTN_REL: + style = ext->styles_btn[LV_BTN_STATE_REL]; + break; + case LV_LIST_STYLE_BTN_PR: + style = ext->styles_btn[LV_BTN_STATE_PR]; + break; + case LV_LIST_STYLE_BTN_TGL_REL: + style = ext->styles_btn[LV_BTN_STATE_TGL_REL]; + break; + case LV_LIST_STYLE_BTN_TGL_PR: + style = ext->styles_btn[LV_BTN_STATE_TGL_PR]; + break; + case LV_LIST_STYLE_BTN_INA: + style = ext->styles_btn[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list) +{ + /*Search the first list element which 'y' coordinate is below the parent + * and position the list to show this element on the bottom*/ + lv_obj_t * scrl = lv_page_get_scrl(list); + lv_obj_t * e; + lv_obj_t * e_prev = NULL; + e = lv_list_get_prev_btn(list, NULL); + while(e != NULL) { + if(e->coords.y2 <= list->coords.y2) { + if(e_prev != NULL) { + lv_coord_t new_y = lv_obj_get_height(list) - (lv_obj_get_y(e_prev) + lv_obj_get_height(e_prev)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->anim_time == 0) { + lv_obj_set_y(scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_LIST_FOCUS_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + } + break; + } + e_prev = e; + e = lv_list_get_prev_btn(list, e); + } +} + +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list) +{ + /*Search the first list element which 'y' coordinate is above the parent + * and position the list to show this element on the top*/ + lv_obj_t * scrl = lv_page_get_scrl(list); + lv_obj_t * e; + e = lv_list_get_prev_btn(list, NULL); + while(e != NULL) { + if(e->coords.y1 < list->coords.y1) { + lv_coord_t new_y = -lv_obj_get_y(e); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->anim_time == 0) { + lv_obj_set_y(scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_LIST_FOCUS_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + +#endif + } + break; + } + e = lv_list_get_prev_btn(list, e); + } +} + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t * btn, bool anim_en) +{ + +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + + lv_page_focus(list, btn, anim_en == false ? 0 : lv_list_get_anim_time(list)); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the list + * @param list pointer to a list object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_page_signal(list, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CORD_CHG) { + /*Be sure the width of the buttons are correct*/ + lv_coord_t w = lv_obj_get_width(list); + if(w != lv_area_get_width(param)) { /*Width changed*/ + refr_btn_width(list); + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Because of the possible change of horizontal and vertical padding refresh buttons width */ + refr_btn_width(list); + } else if(sign == LV_SIGNAL_FOCUS) { + +#if USE_LV_GROUP + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*With ENCODER select the first button only in edit mode*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + lv_group_t * g = lv_obj_get_group(list); + if(lv_group_get_editing(g)) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->last_sel) { + /* Select the last used button */ + lv_list_set_btn_selected(list, ext->last_sel); + } + else { + /*Get the first button and mark it as selected*/ + lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL)); + } + } else { + lv_list_set_btn_selected(list, NULL); + } + } + /*Else select the clicked button*/ + else { + /*Mark the last clicked button (if any) as selected because it triggered the focus*/ + if(last_clicked_btn) { + lv_list_set_btn_selected(list, last_clicked_btn); + } else { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->last_sel) { + /* Select the last used button */ + lv_list_set_btn_selected(list, ext->last_sel); + } + else { + /*Get the first button and mark it as selected*/ + lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL)); + } + } + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { + +#if USE_LV_GROUP + /*De-select the selected btn*/ + lv_list_set_btn_selected(list, NULL); + last_clicked_btn = NULL; /*button click will be set if click happens before focus*/ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->selected_btn = NULL; +#endif + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_CONTROLL) { + +#if USE_LV_GROUP + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + /*If there is a valid selected button the make the previous selected*/ + if(ext->selected_btn) { + lv_obj_t * btn_prev = lv_list_get_next_btn(list, ext->selected_btn); + if(btn_prev) lv_list_set_btn_selected(list, btn_prev); + } + /*If there is no selected button the make the first selected*/ + else { + lv_obj_t * btn = lv_list_get_next_btn(list, NULL); + if(btn) lv_list_set_btn_selected(list, btn); /*If there are no buttons on the list then there is no first button*/ + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + /*If there is a valid selected button the make the next selected*/ + if(ext->selected_btn != NULL) { + lv_obj_t * btn_next = lv_list_get_prev_btn(list, ext->selected_btn); + if(btn_next) lv_list_set_btn_selected(list, btn_next); + } + /*If there is no selected button the make the first selected*/ + else { + lv_obj_t * btn = lv_list_get_next_btn(list, NULL); + if(btn) lv_list_set_btn_selected(list, btn); + } + } else if(c == LV_GROUP_KEY_ENTER) { + /*Get the 'pressed' button*/ + lv_obj_t * btn = NULL; + btn = lv_list_get_prev_btn(list, btn); + while(btn != NULL) { + if(lv_btn_get_state(btn) == LV_BTN_STATE_PR) break; + btn = lv_list_get_prev_btn(list, btn); + } + + if(btn != NULL) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->last_sel = btn; + lv_action_t rel_action; + rel_action = lv_btn_get_action(btn, LV_BTN_ACTION_CLICK); + if(rel_action != NULL) rel_action(btn); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_list"; + } + return res; +} + + +/** + * Signal function of the list buttons + * @param btn pointer to a button on the list + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_btn_signal(btn, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_RELEASED) { + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->page.scroll_prop_ip = 0; + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(list); + if(lv_group_get_focused(g) == list && lv_indev_is_dragging(lv_indev_get_act()) == false) { + /* Is the list is focused then be sure only the button being released + * has a pressed state to indicate the selected state on the list*/ + lv_obj_t * btn_i = lv_list_get_prev_btn(list, NULL); + while(btn_i) { + lv_btn_state_t s = lv_btn_get_state(btn_i); + if(s == LV_BTN_STATE_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_REL); + else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_TGL_REL); + btn_i = lv_list_get_prev_btn(list, btn_i); + } + + /*Make the released button "selected"*/ + lv_list_set_btn_selected(list, btn); + } + + /* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus + * to mark it as selected (pressed state)*/ + last_clicked_btn = btn; +#endif + if(lv_indev_is_dragging(lv_indev_get_act()) == false && ext->single_mode) + { + lv_list_btn_single_selected(btn); + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->page.scroll_prop_ip = 0; + } + else if(sign == LV_SIGNAL_CLEANUP) { + +#if USE_LV_GROUP + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_obj_t * sel = lv_list_get_btn_selected(list); + if(sel == btn) lv_list_set_btn_selected(list, lv_list_get_next_btn(list, btn)); +#endif + } + + + return res; +} + +static void refr_btn_width(lv_obj_t * list) +{ + lv_style_t * style = lv_list_get_style(list, LV_LIST_STYLE_BG); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(list)); + lv_coord_t w = lv_obj_get_width(list); + lv_coord_t btn_w = w - (style->body.padding.hor + style_scrl->body.padding.hor) * 2; + + lv_obj_t * btn = lv_list_get_prev_btn(list, NULL); + while(btn) { + /*Make the size adjustment for each buttons*/ + if(lv_obj_get_width(btn) != btn_w) { + lv_obj_set_width(btn, btn_w); + /*Set the label size to roll its text*/ + lv_obj_t * label = lv_list_get_btn_label(btn); + lv_obj_set_width(label, btn->coords.x2 - label->coords.x1); + lv_label_set_text(label, NULL); + } + btn = lv_list_get_prev_btn(list, btn); + } +} + +/** + * Make a single button selected in the list, deselect others, should be called in list btns call back. + * @param btn pointer to the currently pressed list btn object + */ +static void lv_list_btn_single_selected(lv_obj_t *btn) +{ + lv_obj_t *list = lv_obj_get_parent(lv_obj_get_parent(btn)); + + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + do + { + if(e == btn) + { + lv_btn_set_state(e, LV_BTN_STATE_TGL_REL); + } + else + { + lv_btn_set_state(e, LV_BTN_STATE_REL); + } + e = lv_list_get_next_btn(list, e); + } while (e != NULL); +} + +/** + * Check if this is really a list button or another object. + * @param list_btn List button + */ +static bool lv_list_is_list_btn(lv_obj_t * list_btn) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_btn, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_btn")) + return true; + } + return false; +} + +/** + * Check if this is really a list label or another object. + * @param list_label List label + */ +static bool lv_list_is_list_label(lv_obj_t * list_label) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_label, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_label")) + return true; + } + return false; +} + +/** + * Check if this is really a list image or another object. + * @param list_image List image + */ +static bool lv_list_is_list_img(lv_obj_t * list_img) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_img, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_img")) + return true; + } + return false; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_list.h b/bdk/libs/lvgl/lv_objx/lv_list.h new file mode 100644 index 0000000..01ebb19 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_list.h @@ -0,0 +1,336 @@ +/** + * @file lv_list.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_BTN == 0 +#error "lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "../lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t anim_time; /*Scroll animation time*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/ + lv_style_t *style_img; /*Style of the list element images on buttons*/ + uint32_t size; /*the number of items(buttons) in the list*/ + bool single_mode; /* whether single selected mode is enabled */ +#if USE_LV_GROUP + lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ + lv_obj_t * selected_btn; /* The button is currently being selected*/ +#endif +} lv_list_ext_t; + +enum { + LV_LIST_STYLE_BG, + LV_LIST_STYLE_SCRL, + LV_LIST_STYLE_SB, + LV_LIST_STYLE_EDGE_FLASH, + LV_LIST_STYLE_BTN_REL, + LV_LIST_STYLE_BTN_PR, + LV_LIST_STYLE_BTN_TGL_REL, + LV_LIST_STYLE_BTN_TGL_PR, + LV_LIST_STYLE_BTN_INA, +}; +typedef uint8_t lv_list_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action); + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode); + +#if USE_LV_GROUP + +/** + * Make a button selected. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @param btn pointer to a button to select + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn); +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time); + +/** + * Set the scroll bar mode of a list + * @param list pointer to a list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(list, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll. + * @param list pointer to a List + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en) +{ + lv_page_set_scroll_propagation(list, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param list pointer to a List + * @param en true or false to enable/disable end flash + */ +static inline void lv_list_set_edge_flash(lv_obj_t * list, bool en) +{ + lv_page_set_edge_flash(list, en); +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list); + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn); +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn); + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn); + +/** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn); + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list); + +#if USE_LV_GROUP +/** + * Get the currently selected button. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); +#endif + + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t *list); + + +/** + * Get the scroll bar mode of a list + * @param list pointer to a list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list) +{ + return lv_page_get_sb_mode(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_scroll_propagation(lv_obj_t * list) +{ + return lv_page_get_scroll_propagation(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_edge_flash(lv_obj_t * list) +{ + return lv_page_get_edge_flash(list); +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list); +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list); + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t *btn, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LIST_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_lmeter.c b/bdk/libs/lvgl/lv_objx/lv_lmeter.c new file mode 100644 index 0000000..4d78d8e --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_lmeter.c @@ -0,0 +1,382 @@ +/** + * @file lv_lmeter.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_lmeter.h" +#if USE_LV_LMETER != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_core/lv_group.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_LMETER_LINE_UPSCALE 5 /*2^x upscale of line to make rounding*/ +#define LV_LMETER_LINE_UPSCALE_MASK ((1 << LV_LMETER_LINE_UPSCALE) - 1) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param); +static lv_coord_t lv_lmeter_coord_round(int32_t x); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("line meter create started"); + + /*Create the ancestor of line meter*/ + lv_obj_t * new_lmeter = lv_obj_create(par, copy); + lv_mem_assert(new_lmeter); + if(new_lmeter == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_lmeter); + + /*Allocate the line meter type specific extended data*/ + lv_lmeter_ext_t * ext = lv_obj_allocate_ext_attr(new_lmeter, sizeof(lv_lmeter_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->min_value = 0; + ext->max_value = 100; + ext->cur_value = 0; + ext->line_cnt = 21; /*Odd scale number looks better*/ + ext->scale_angle = 240; /*(scale_num - 1) * N looks better */ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_lmeter, lv_lmeter_signal); + lv_obj_set_design_func(new_lmeter, lv_lmeter_design); + + /*Init the new line meter line meter*/ + if(copy == NULL) { + lv_obj_set_size(new_lmeter, LV_DPI, LV_DPI); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_lmeter_set_style(new_lmeter, th->lmeter); + } else { + lv_lmeter_set_style(new_lmeter, &lv_style_pretty_color); + } + } + /*Copy an existing line meter*/ + else { + lv_lmeter_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->scale_angle = copy_ext->scale_angle; + ext->line_cnt = copy_ext->line_cnt; + ext->min_value = copy_ext->min_value; + ext->max_value = copy_ext->max_value; + ext->cur_value = copy_ext->cur_value; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_lmeter); + } + + LV_LOG_INFO("line meter created"); + + return new_lmeter; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t * lmeter, int16_t value) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->cur_value == value) return; + + ext->cur_value = value > ext->max_value ? ext->max_value : value; + ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value; + lv_obj_invalidate(lmeter); +} + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t * lmeter, int16_t min, int16_t max) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->min_value == min && ext->max_value == max) return; + + ext->max_value = max; + ext->min_value = min; + if(ext->cur_value > max) { + ext->cur_value = max; + lv_lmeter_set_value(lmeter, ext->cur_value); + } + if(ext->cur_value < min) { + ext->cur_value = min; + lv_lmeter_set_value(lmeter, ext->cur_value); + } + lv_obj_invalidate(lmeter); +} + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->scale_angle == angle && ext->line_cnt == line_cnt) return; + + ext->scale_angle = angle; + ext->line_cnt = line_cnt; + + lv_obj_invalidate(lmeter); +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->cur_value; +} + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->min_value; +} + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->max_value; +} + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->line_cnt ; +} + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->scale_angle; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the line meters + * @param lmeter pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + lv_style_t * style = lv_obj_get_style(lmeter); + lv_opa_t opa_scale = lv_obj_get_opa_scale(lmeter); + lv_style_t style_tmp; + memcpy(&style_tmp, style, sizeof(lv_style_t)); + + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(lmeter); + if(lv_group_get_focused(g) == lmeter) { + style_tmp.line.width += 1; + } +#endif + + lv_coord_t r_out = lv_obj_get_width(lmeter) / 2; + lv_coord_t r_in = r_out - style->body.padding.hor; + if(r_in < 1) r_in = 1; + + lv_coord_t x_ofs = lv_obj_get_width(lmeter) / 2 + lmeter->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(lmeter) / 2 + lmeter->coords.y1; + int16_t angle_ofs = 90 + (360 - ext->scale_angle) / 2; + int16_t level = (int32_t)((int32_t)(ext->cur_value - ext->min_value) * ext->line_cnt) / (ext->max_value - ext->min_value); + uint8_t i; + + style_tmp.line.color = style->body.main_color; + + /*Calculate every coordinate in a bigger size to make rounding later*/ + r_out = r_out << LV_LMETER_LINE_UPSCALE; + r_in = r_in << LV_LMETER_LINE_UPSCALE; + + for(i = 0; i < ext->line_cnt; i++) { + /*Calculate the position a scale label*/ + int16_t angle = (i * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs; + + lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> LV_TRIGO_SHIFT; + lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> LV_TRIGO_SHIFT; + lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> LV_TRIGO_SHIFT; + lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> LV_TRIGO_SHIFT; + + /*Rounding*/ + x_out = lv_lmeter_coord_round(x_out); + x_in = lv_lmeter_coord_round(x_in); + y_out = lv_lmeter_coord_round(y_out); + y_in = lv_lmeter_coord_round(y_in); + + lv_point_t p1; + lv_point_t p2; + + p2.x = x_in + x_ofs; + p2.y = y_in + y_ofs; + + p1.x = x_out + x_ofs; + p1.y = y_out + y_ofs; + + if(i >= level) style_tmp.line.color = style->line.color; + else { + style_tmp.line.color = lv_color_mix(style->body.grad_color, style->body.main_color, (255 * i) / ext->line_cnt); + } + + lv_draw_line(&p1, &p2, mask, &style_tmp, opa_scale); + } + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the line meter + * @param lmeter pointer to a line meter object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(lmeter, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_refresh_ext_size(lmeter); + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_lmeter_get_style(lmeter); + lmeter->ext_size = LV_MATH_MAX(lmeter->ext_size, style->line.width); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_lmeter"; + } + + return res; +} + +/** + * Round a coordinate which is upscaled (>=x.5 -> x + 1; x) + * @param x a coordinate which is greater then it should be + * @return the downscaled and rounded coordinate (+-1) + */ +static lv_coord_t lv_lmeter_coord_round(int32_t x) +{ +#if LV_LMETER_LINE_UPSCALE > 0 + bool was_negative = false; + if(x < 0) { + was_negative = true; + x = -x; + } + + x = (x >> LV_LMETER_LINE_UPSCALE) + ((x & LV_LMETER_LINE_UPSCALE_MASK) >> (LV_LMETER_LINE_UPSCALE - 1)); + + if(was_negative) x = -x; + + return x; +#else + return x; +#endif +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_lmeter.h b/bdk/libs/lvgl/lv_objx/lv_lmeter.h new file mode 100644 index 0000000..0235d34 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_lmeter.h @@ -0,0 +1,153 @@ +/** + * @file lv_lmeter.h + * + */ + +#ifndef LV_LMETER_H +#define LV_LMETER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LMETER != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of line meter*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ + uint8_t line_cnt; /*Count of lines */ + int16_t cur_value; + int16_t min_value; + int16_t max_value; +} lv_lmeter_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value); + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max); + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt); + +/** + * Set the styles of a line meter + * @param lmeter pointer to a line meter object + * @param bg set the style of the line meter + */ +static inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg) +{ + lv_obj_set_style(lmeter, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t *lmeter); + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter); + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter); + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter); + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter); + +/** + * Get the style of a line meter + * @param lmeter pointer to a line meter object + * @return pointer to the line meter's style + */ +static inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter) +{ + return lv_obj_get_style(lmeter); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LMETER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LMETER_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_mbox.c b/bdk/libs/lvgl/lv_objx/lv_mbox.c new file mode 100644 index 0000000..4dcacdd --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_mbox.c @@ -0,0 +1,532 @@ +/* + * 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 . + */ + +/** + * @file lv_mbox.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_mbox.h" +#if USE_LV_MBOX != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +#if USE_LV_ANIMATION +# ifndef LV_MBOX_CLOSE_ANIM_TIME +# define LV_MBOX_CLOSE_ANIM_TIME 200 /*List close animation time) */ +# endif +#else +# undef LV_MBOX_CLOSE_ANIM_TIME +# define LV_MBOX_CLOSE_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param); +static void mbox_realign(lv_obj_t * mbox); +static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt); +#if USE_LV_ANIMATION +static void lv_mbox_close_end_cb(lv_obj_t * mbox); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("mesasge box create started"); + + /*Create the ancestor message box*/ + lv_obj_t * new_mbox = lv_cont_create(par, copy); + lv_mem_assert(new_mbox); + if(new_mbox == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_mbox); + + /*Allocate the message box type specific extended data*/ + lv_mbox_ext_t * ext = lv_obj_allocate_ext_attr(new_mbox, sizeof(lv_mbox_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->text = NULL; + ext->btnm = NULL; + ext->anim_time = LV_MBOX_CLOSE_ANIM_TIME; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_mbox, lv_mbox_signal); + + /*Init the new message box message box*/ + if(copy == NULL) { + ext->text = lv_label_create(new_mbox, NULL); + lv_label_set_align(ext->text, LV_LABEL_ALIGN_CENTER); + lv_label_set_long_mode(ext->text, LV_LABEL_LONG_BREAK); + lv_label_set_text(ext->text, "Message"); + + lv_cont_set_layout(new_mbox, LV_LAYOUT_COL_M); + lv_cont_set_fit(new_mbox, false, true); + lv_obj_set_width(new_mbox, LV_HOR_RES / 2); + lv_obj_align(new_mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, th->mbox.bg); + } else { + lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, &lv_style_pretty); + } + + } + /*Copy an existing message box*/ + else { + lv_mbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + ext->text = lv_label_create(new_mbox, copy_ext->text); + + /*Copy the buttons and the label on them*/ + if(copy_ext->btnm) ext->btnm = lv_btnm_create(new_mbox, copy_ext->btnm); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_mbox); + } + + + LV_LOG_INFO("mesasge box created"); + + return new_mbox; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char ** btn_map, lv_btnm_action_t action) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + /*Create a button matrix if not exists yet*/ + if(ext->btnm == NULL) { + ext->btnm = lv_btnm_create(mbox, NULL); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_BG, th->mbox.btn.bg); + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_REL, th->mbox.btn.rel); + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_PR, th->mbox.btn.pr); + } else { + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, &lv_style_transp_fit); + } + } + + lv_btnm_set_map(ext->btnm, btn_map); + if(action == NULL) lv_btnm_set_action(ext->btnm, lv_mbox_close_action); /*Set a default action anyway*/ + else lv_btnm_set_action(ext->btnm, action); + + mbox_realign(mbox); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + lv_label_set_text(ext->text, txt); + + mbox_realign(mbox); +} + + +/** + * Stop the action to call when button is released + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + * @param pointer to an 'lv_btnm_action_t' action + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + lv_btnm_set_action(ext->btnm, action); +} + + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + ext->anim_time = anim_time; +} + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay) +{ +#if USE_LV_ANIMATION + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(ext->anim_time != 0) { + /*Add shrinking animations*/ + lv_obj_animate(mbox, LV_ANIM_GROW_H | LV_ANIM_OUT, ext->anim_time, delay, NULL); + lv_obj_animate(mbox, LV_ANIM_GROW_V | LV_ANIM_OUT, ext->anim_time, delay, lv_mbox_close_end_cb); + + /*Disable fit to let shrinking work*/ + lv_cont_set_fit(mbox, false, false); + } else { + lv_obj_animate(mbox, LV_ANIM_NONE, ext->anim_time, delay, lv_mbox_close_end_cb); + } +#else + (void)delay; /*Unused*/ + lv_obj_del(mbox); +#endif +} + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox) +{ +#if USE_LV_ANIMATION + lv_anim_del(mbox, NULL); +#else + (void)mbox; /*Unused*/ +#endif +} + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t * mbox, lv_mbox_style_t type, lv_style_t * style) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + switch(type) { + case LV_MBOX_STYLE_BG: + lv_obj_set_style(mbox, style); + break; + case LV_MBOX_STYLE_BTN_BG: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, style); + break; + case LV_MBOX_STYLE_BTN_REL: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_REL, style); + break; + case LV_MBOX_STYLE_BTN_PR: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_MBOX_STYLE_BTN_TGL_REL: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_MBOX_STYLE_BTN_TGL_PR: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_MBOX_STYLE_BTN_INA: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_INA, style); + break; + } + + mbox_realign(mbox); + +} + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(ext->btnm) + lv_btnm_set_recolor(ext->btnm, en); +} + +void lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if (ext->text) + lv_label_set_recolor(ext->text, en); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + return lv_label_get_text(ext->text); +} + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn) +{ + lv_obj_t * mbox = lv_obj_get_parent(btn); + + return mbox; +} + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + return ext->anim_time; +} + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t * mbox, lv_mbox_style_t type) +{ + lv_style_t * style = NULL; + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + switch(type) { + case LV_MBOX_STYLE_BG: + style = lv_obj_get_style(mbox); + break; + case LV_MBOX_STYLE_BTN_BG: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BG); + break; + case LV_MBOX_STYLE_BTN_REL: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_REL); + break; + case LV_MBOX_STYLE_BTN_PR: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_PR); + break; + case LV_MBOX_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_MBOX_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR); + break; + case LV_MBOX_STYLE_BTN_INA: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(!ext->btnm) + return false; + + return lv_btnm_get_recolor(ext->btnm); +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the message box + * @param mbox pointer to a message box object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /*Translate LV_GROUP_KEY_UP/DOWN to LV_GROUP_KEY_LEFT/RIGHT */ + char c_trans = 0; + if(sign == LV_SIGNAL_CONTROLL) { + c_trans = *((char *)param); + if(c_trans == LV_GROUP_KEY_DOWN) c_trans = LV_GROUP_KEY_LEFT; + if(c_trans == LV_GROUP_KEY_UP) c_trans = LV_GROUP_KEY_RIGHT; + + param = &c_trans; + } + + /* Include the ancient signal function */ + res = ancestor_signal(mbox, sign, param); + if(res != LV_RES_OK) return res; + + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_obj_get_width(mbox) != lv_area_get_width(param)) { + mbox_realign(mbox); + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + mbox_realign(mbox); + + } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS || + sign == LV_SIGNAL_CONTROLL || sign == LV_SIGNAL_GET_EDITABLE) { + if(ext->btnm) { + ext->btnm->signal_func(ext->btnm, sign, param); + } + + /* The button matrix with ENCODER input supposes it's in a group but in this case it isn't (Only the message box's container) + * So so some actions here instead*/ + if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_indev_t * indev = lv_indev_get_act(); + lv_hal_indev_type_t indev_type = lv_indev_get_type(indev); + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigation mode don't select any button but in edit mode select the fist*/ + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btnm); + if(lv_group_get_editing(lv_obj_get_group(mbox))) btnm_ext->btn_id_pr = 0; + else btnm_ext->btn_id_pr = LV_BTNM_PR_NONE; + } +#endif + } + + + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_mbox"; + } + + return res; +} + +/** + * Resize the button holder to fit + * @param mbox pointer to message box object + */ +static void mbox_realign(lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + lv_style_t * style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BG); + lv_coord_t w = lv_obj_get_width(mbox) - 2 * style->body.padding.hor; + + if(ext->text) { + lv_obj_set_width(ext->text, w); + } + + if(ext->btnm) { + lv_style_t * btn_bg_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_BG); + lv_style_t * btn_rel_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_REL); + lv_coord_t font_h = lv_font_get_height(btn_rel_style->text.font); + lv_obj_set_size(ext->btnm, w, font_h + 2 * btn_rel_style->body.padding.ver + 2 * btn_bg_style->body.padding.ver); + } +} + +static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt) +{ + lv_obj_t * mbox = lv_mbox_get_from_btn(btn); + + if(txt[0] != '\0') { + lv_mbox_start_auto_close(mbox, 0); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +#if USE_LV_ANIMATION +static void lv_mbox_close_end_cb(lv_obj_t * mbox) +{ + lv_obj_del(mbox); +} +#endif +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_mbox.h b/bdk/libs/lvgl/lv_objx/lv_mbox.h new file mode 100644 index 0000000..ae5c76a --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_mbox.h @@ -0,0 +1,221 @@ +/* + * 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 . + */ + +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MBOX_H +#define LV_MBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_MBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#if USE_LV_BTNM == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btnm.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of message box*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *text; /*Text of the message box*/ + lv_obj_t *btnm; /*Button matrix for the buttons*/ + uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ +} lv_mbox_ext_t; + +enum { + LV_MBOX_STYLE_BG, + LV_MBOX_STYLE_BTN_BG, + LV_MBOX_STYLE_BTN_REL, + LV_MBOX_STYLE_BTN_PR, + LV_MBOX_STYLE_BTN_TGL_REL, + LV_MBOX_STYLE_BTN_TGL_PR, + LV_MBOX_STYLE_BTN_INA, +}; +typedef uint8_t lv_mbox_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt); + +/** + * Stop the action to call when button is released + * @param mbox pointer to a message box object + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action); + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time); + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay); + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox); + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`. + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en); + +void lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox); + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn); + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox); + + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type); + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + + +#endif /*USE_LV_MBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MBOX_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_objx.mk b/bdk/libs/lvgl/lv_objx/lv_objx.mk new file mode 100644 index 0000000..d35252b --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_objx.mk @@ -0,0 +1,36 @@ +CSRCS += lv_arc.c +CSRCS += lv_bar.c +CSRCS += lv_cb.c +CSRCS += lv_ddlist.c +CSRCS += lv_kb.c +CSRCS += lv_line.c +CSRCS += lv_mbox.c +CSRCS += lv_preload.c +CSRCS += lv_roller.c +CSRCS += lv_table.c +CSRCS += lv_tabview.c +CSRCS += lv_tileview.c +CSRCS += lv_btn.c +CSRCS += lv_calendar.c +CSRCS += lv_chart.c +CSRCS += lv_canvas.c +CSRCS += lv_gauge.c +CSRCS += lv_label.c +CSRCS += lv_list.c +CSRCS += lv_slider.c +CSRCS += lv_ta.c +CSRCS += lv_spinbox.c +CSRCS += lv_btnm.c +CSRCS += lv_cont.c +CSRCS += lv_img.c +CSRCS += lv_imgbtn.c +CSRCS += lv_led.c +CSRCS += lv_lmeter.c +CSRCS += lv_page.c +CSRCS += lv_sw.c +CSRCS += lv_win.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx +VPATH += :$(LVGL_DIR)/lvgl/lv_objx + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx" diff --git a/bdk/libs/lvgl/lv_objx/lv_objx_templ.c b/bdk/libs/lvgl/lv_objx/lv_objx_templ.c new file mode 100644 index 0000000..f605450 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_objx_templ.c @@ -0,0 +1,231 @@ +/** + * @file lv_templ.c + * + */ + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +/********************* + * INCLUDES + *********************/ +//#include "lv_templ.h" /*TODO uncomment this*/ +#if USE_LV_TEMPL != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a template object + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("template create started"); + + /*Create the ancestor of template*/ + /*TODO modify it to the ancestor create function */ + lv_obj_t * new_templ = lv_ANCESTOR_create(par, copy); + lv_mem_assert(new_templ); + if(new_templ == NULL) return NULL; + + /*Allocate the template type specific extended data*/ + lv_templ_ext_t * ext = lv_obj_allocate_ext_attr(new_templ, sizeof(lv_templ_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_templ); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_templ); + + /*Initialize the allocated 'ext' */ + ext->xyz = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_templ, lv_templ_signal); + lv_obj_set_design_func(new_templ, lv_templ_design); + + /*Init the new template template*/ + if(copy == NULL) { + + } + /*Copy an existing template*/ + else { + lv_templ_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_templ); + } + + LV_LOG_INFO("template created"); + + return new_templ; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/* + * New object specific "set" functions come here + */ + + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t * style) +{ + lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ); + + switch(type) { + case LV_TEMPL_STYLE_X: + break; + case LV_TEMPL_STYLE_Y: + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/* + * New object specific "get" functions come here + */ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type) +{ + lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ); + lv_style_t * style = NULL; + + switch(type) { + case LV_TEMPL_STYLE_X: + style = NULL; /*Replace NULL with a pointer to the style*/ + case LV_TEMPL_STYLE_Y: + style = NULL; /*Replace NULL with a pointer to the style*/ + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the templates + * @param templ pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the template + * @param templ pointer to a template object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(templ, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_templ"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_objx_templ.h b/bdk/libs/lvgl/lv_objx/lv_objx_templ.h new file mode 100644 index 0000000..ab6d090 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_objx_templ.h @@ -0,0 +1,111 @@ +/** + * @file lv_templ.h + * + */ + + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TEMPL != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_templ_ext_t; + + +/*Styles*/ +enum { + LV_TEMPL_STYLE_X, + LV_TEMPL_STYLE_Y, +}; +typedef uint8_t lv_templ_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a template objects + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TEMPL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_page.c b/bdk/libs/lvgl/lv_objx/lv_page.c new file mode 100644 index 0000000..65dcb35 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_page.c @@ -0,0 +1,1205 @@ +/* + * 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 . + */ + +/** + * @file lv_page.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_objx/lv_page.h" +#if USE_LV_PAGE != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_core/lv_refr.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_PAGE_SB_MIN_SIZE (LV_DPI / 8) +#define LV_PAGE_SCROLL_ANIM_TIME 200 /*[ms] Scroll anim time on `lv_page_scroll_up/down/left/rigth`*/ +#define LV_PAGE_END_FLASH_SIZE (LV_DPI / 4) +#define LV_PAGE_END_ANIM_TIME 300 +#define LV_PAGE_END_ANIM_WAIT_TIME 300 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_page_sb_refresh(lv_obj_t * page); +static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param); +static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +#if USE_LV_ANIMATION +static void edge_flash_anim(void * page, int32_t v); +static void edge_flash_anim_end(void * page); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("page create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_page = lv_cont_create(par, copy); + lv_mem_assert(new_page); + if(new_page == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_page); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_page); + + /*Allocate the object type specific extended data*/ + lv_page_ext_t * ext = lv_obj_allocate_ext_attr(new_page, sizeof(lv_page_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->scrl = NULL; + ext->pr_action = NULL; + ext->rel_action = NULL; + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + ext->bgo = NULL; + ext->pr = NULL; + ext->sb.style = &lv_style_pretty; + ext->sb.mode = LV_SB_MODE_AUTO; + ext->edge_flash.enabled = 0; + ext->edge_flash.bottom_ip = 0; + ext->edge_flash.top_ip = 0; + ext->edge_flash.left_ip = 0; + ext->edge_flash.right_ip = 0; + ext->edge_flash.state = 0; + ext->edge_flash.style = &lv_style_plain_color; + ext->arrow_scroll = 0; + ext->scroll_prop = 0; + ext->scroll_prop_ip = 0; + + /*Init the new page object*/ + if(copy == NULL) { + ext->scrl = lv_cont_create(new_page, NULL); + lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal); + lv_obj_set_design_func(ext->scrl, lv_scrl_design); + lv_obj_set_drag(ext->scrl, true); + lv_obj_set_drag_throw(ext->scrl, true); + lv_obj_set_protect(ext->scrl, LV_PROTECT_PARENT | LV_PROTECT_PRESS_LOST); + lv_cont_set_fit(ext->scrl, false, true); + + /* Add the signal function only if 'scrolling' is created + * because everything has to be ready before any signal is received*/ + lv_obj_set_signal_func(new_page, lv_page_signal); + lv_obj_set_design_func(new_page, lv_page_design); + + lv_page_set_sb_mode(new_page, ext->sb.mode); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + if(par == NULL) { /*Different styles if it is screen*/ + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->bg); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_transp); + } else { + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->page.bg); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, th->page.scrl); + + } + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, th->page.sb); + } else { + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, &lv_style_pretty_color); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_pretty); + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, &lv_style_pretty_color); + } + + } else { + lv_page_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->scrl = lv_cont_create(new_page, copy_ext->scrl); + ext->bgo = lv_page_get_style(copy, LV_PAGE_STYLE_BGO); + ext->pr = lv_page_get_style(copy, LV_PAGE_STYLE_PR); + lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal); + + lv_page_set_pr_action(new_page, copy_ext->pr_action); + lv_page_set_rel_action(new_page, copy_ext->rel_action); + lv_page_set_sb_mode(new_page, copy_ext->sb.mode); + lv_page_set_arrow_scroll(new_page, copy_ext->arrow_scroll); + + + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, lv_page_get_style(copy, LV_PAGE_STYLE_BG)); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy, LV_PAGE_STYLE_SCRL)); + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, lv_page_get_style(copy, LV_PAGE_STYLE_SB)); + + /* Add the signal function only if 'scrolling' is created + * because everything has to be ready before any signal is received*/ + lv_obj_set_signal_func(new_page, lv_page_signal); + lv_obj_set_design_func(new_page, lv_page_design); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_page); + } + + lv_page_sb_refresh(new_page); + + LV_LOG_INFO("page created"); + + return new_page; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is release + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->rel_action = rel_action; +} + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->pr_action = pr_action; +} + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + if(ext->sb.mode == sb_mode) return; + + if(sb_mode == LV_SB_MODE_HIDE) ext->sb.mode |= LV_SB_MODE_HIDE; /*Set the hidden flag*/ + else if(sb_mode == LV_SB_MODE_UNHIDE) ext->sb.mode &= (~LV_SB_MODE_HIDE); /*Clear the hidden flag*/ + else { + if(ext->sb.mode & LV_SB_MODE_HIDE) sb_mode |= LV_SB_MODE_HIDE; + ext->sb.mode = sb_mode; + } + + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + + lv_page_sb_refresh(page); + lv_obj_invalidate(page); +} + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->arrow_scroll = en ? 1 : 0; +} + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->scroll_prop = en ? 1 : 0; +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.enabled = en ? 1 : 0; +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_page_set_style(lv_obj_t * page, lv_page_style_t type, lv_style_t * style) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + switch(type) { + case LV_PAGE_STYLE_BG: + lv_obj_set_style(page, style); + break; + case LV_PAGE_STYLE_BGO: + ext->bgo = style; + break; + case LV_PAGE_STYLE_PR: + ext->pr = style; + break; + case LV_PAGE_STYLE_SCRL: + lv_obj_set_style(ext->scrl, style); + break; + case LV_PAGE_STYLE_SB: + ext->sb.style = style; + lv_area_set_height(&ext->sb.hor_area, ext->sb.style->body.padding.inner); + lv_area_set_width(&ext->sb.ver_area, ext->sb.style->body.padding.inner); + lv_page_sb_refresh(page); + lv_obj_refresh_ext_size(page); + lv_obj_invalidate(page); + break; + case LV_PAGE_STYLE_EDGE_FLASH: + ext->edge_flash.style = style; + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + return ext->scrl; +} + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->pr_action; +} + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->rel_action; +} + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->sb.mode; +} + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->arrow_scroll ? true : false; +} + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->scroll_prop == 0 ? false : true; +} + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->edge_flash.enabled == 0 ? false : true; +} + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page) +{ + lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + return lv_obj_get_width(page) - 2 * (bg_style->body.padding.hor + scrl_style->body.padding.hor); +} + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page) +{ + lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + return lv_obj_get_height(page) - 2 * (bg_style->body.padding.ver + scrl_style->body.padding.ver); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_page_get_style(const lv_obj_t * page, lv_page_style_t type) +{ + lv_style_t * style = NULL; + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + switch(type) { + case LV_PAGE_STYLE_BG: + style = lv_obj_get_style(page); + break; + case LV_PAGE_STYLE_BGO: + style = ext->bgo; + break; + case LV_PAGE_STYLE_PR: + style = ext->pr; + break; + case LV_PAGE_STYLE_SCRL: + style = lv_obj_get_style(ext->scrl); + break; + case LV_PAGE_STYLE_SB: + style = ext->sb.style; + break; + case LV_PAGE_STYLE_EDGE_FLASH: + style = ext->edge_flash.style; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue) +{ + lv_obj_set_drag_parent(obj, glue); + lv_obj_set_drag(obj, glue); +} + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#else + /* Be sure there is no position changing animation in progress + * because it can overide the current changes*/ + lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_y); + lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_pos); + lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_y); + lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_pos); +#endif + + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * style_scrl = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1; + lv_coord_t obj_h = lv_obj_get_height(obj); + lv_coord_t scrlable_y = lv_obj_get_y(ext->scrl); + lv_coord_t page_h = lv_obj_get_height(page); + + lv_coord_t top_err = -(scrlable_y + obj_y); + lv_coord_t bot_err = scrlable_y + obj_y + obj_h - page_h; + + /*If obj is higher then the page focus where the "error" is smaller*/ + + /*Out of the page on the top*/ + if((obj_h <= page_h && top_err > 0) || + (obj_h > page_h && top_err < bot_err)) { + /*Calculate a new position and let some space above*/ + scrlable_y = -(obj_y - style_scrl->body.padding.ver - style->body.padding.ver); + scrlable_y += style_scrl->body.padding.ver; + } + /*Out of the page on the bottom*/ + else if((obj_h <= page_h && bot_err > 0) || + (obj_h > page_h && top_err >= bot_err)) { + /*Calculate a new position and let some space below*/ + scrlable_y = -(obj_y + style_scrl->body.padding.ver + style->body.padding.ver); + scrlable_y -= style_scrl->body.padding.ver; + scrlable_y += page_h - obj_h; + } else { + /*Already in focus*/ + return; + } + + if(anim_time == 0) { + lv_obj_set_y(ext->scrl, scrlable_y); +#if USE_LV_ANIMATION + } else { + lv_anim_t a; + a.act_time = 0; + a.start = lv_obj_get_y(ext->scrl); + a.end = scrlable_y; + a.time = anim_time; + a.end_cb = NULL; + a.playback = 0; + a.repeat = 0; + a.var = ext->scrl; + a.path = lv_anim_path_linear; + a.fp = (lv_anim_fp_t) lv_obj_set_y; + lv_anim_create(&a); +#endif + } +} + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist) +{ + lv_obj_t * scrl = lv_page_get_scrl(page); + +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_x(scrl); + a.end = a.start + dist; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_PAGE_SCROLL_ANIM_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#else + lv_obj_set_x(scrl, lv_obj_get_x(scrl) + dist); +#endif +} + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist) +{ + lv_obj_t * scrl = lv_page_get_scrl(page); + +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = a.start + dist; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_PAGE_SCROLL_ANIM_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#else + lv_obj_set_y(scrl, lv_obj_get_y(scrl) + dist); +#endif +} + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page) +{ +#if USE_LV_ANIMATION + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + if(ext->edge_flash.enabled) { + lv_anim_t a; + a.var = page; + a.start = 0; + a.end = LV_PAGE_END_FLASH_SIZE; + a.fp = (lv_anim_fp_t)edge_flash_anim; + a.path = lv_anim_path_linear; + a.end_cb = edge_flash_anim_end; + a.act_time = 0; + a.time = LV_PAGE_END_ANIM_TIME; + a.playback = 1; + a.playback_pause = LV_PAGE_END_ANIM_WAIT_TIME; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the pages + * @param page pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(page, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw without border*/ + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_coord_t border_width_tmp = style->body.border.width; + style->body.border.width = 0; + lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page)); + style->body.border.width = border_width_tmp; + + } else if(mode == LV_DESIGN_DRAW_POST) { /*Draw the scroll bars finally*/ + + /*Draw only a border*/ + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_coord_t shadow_width_tmp = style->body.shadow.width; + uint8_t empty_tmp = style->body.empty; + style->body.shadow.width = 0; + style->body.empty = 1; + lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page)); + style->body.shadow.width = shadow_width_tmp; + style->body.empty = empty_tmp; + + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + /*Draw the scrollbars*/ + lv_area_t sb_area; + if(ext->sb.hor_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) { + /*Convert the relative coordinates to absolute*/ + lv_area_copy(&sb_area, &ext->sb.hor_area); + sb_area.x1 += page->coords.x1; + sb_area.y1 += page->coords.y1; + sb_area.x2 += page->coords.x1; + sb_area.y2 += page->coords.y1; + lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page)); + } + + if(ext->sb.ver_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) { + /*Convert the relative coordinates to absolute*/ + lv_area_copy(&sb_area, &ext->sb.ver_area); + sb_area.x1 += page->coords.x1; + sb_area.y1 += page->coords.y1; + sb_area.x2 += page->coords.x1; + sb_area.y2 += page->coords.y1; + lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page)); + } + + + lv_coord_t page_w = lv_obj_get_width(page); + lv_coord_t page_h = lv_obj_get_height(page); + lv_area_t flash_area; + + if(ext->edge_flash.top_ip) { + flash_area.x1 = page->coords.x1 - page_w; + flash_area.x2 = page->coords.x2 + page_w; + flash_area.y1 = page->coords.y1 - 3 * page_w + ext->edge_flash.state; + flash_area.y2 = page->coords.y1 + ext->edge_flash.state; + } + else if(ext->edge_flash.bottom_ip) { + flash_area.x1 = page->coords.x1 - page_w; + flash_area.x2 = page->coords.x2 + page_w; + flash_area.y1 = page->coords.y2 - ext->edge_flash.state; + flash_area.y2 = page->coords.y2 + 3 * page_w - ext->edge_flash.state; + } + else if(ext->edge_flash.right_ip) { + flash_area.x1 = page->coords.x2 - ext->edge_flash.state; + flash_area.x2 = page->coords.x2 + 3 * page_h - ext->edge_flash.state; + flash_area.y1 = page->coords.y1 - page_h; + flash_area.y2 = page->coords.y2 + page_h; + } + else if(ext->edge_flash.left_ip) { + flash_area.x1 = page->coords.x1 - 3 * page_h + ext->edge_flash.state; + flash_area.x2 = page->coords.x1 + ext->edge_flash.state; + flash_area.y1 = page->coords.y1 - page_h; + flash_area.y2 = page->coords.y2 + page_h; + } + + if(ext->edge_flash.left_ip || ext->edge_flash.right_ip || ext->edge_flash.top_ip || ext->edge_flash.bottom_ip) { + lv_style_t flash_style; + lv_style_copy(&flash_style, ext->edge_flash.style); + flash_style.body.radius = LV_RADIUS_CIRCLE; + uint32_t opa = (flash_style.body.opa * ext->edge_flash.state) / LV_PAGE_END_FLASH_SIZE; + flash_style.body.opa = opa; + lv_draw_rect(&flash_area, mask, &flash_style, lv_obj_get_opa_scale(page)); + } + + } + + return true; +} + +/** + * Handle the drawing related tasks of the scrollable object + * @param scrl pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { +#if USE_LV_GROUP + /* If the page is focused in a group and + * the background object is not visible (transparent or empty) + * then "activate" the style of the scrollable*/ + lv_style_t * style_scrl_ori = lv_obj_get_style(scrl); + lv_obj_t * page = lv_obj_get_parent(scrl); + lv_style_t * style_page = lv_obj_get_style(page); + lv_group_t * g = lv_obj_get_group(page); + if((style_page->body.empty || style_page->body.opa == LV_OPA_TRANSP) && style_page->body.border.width == 0) { /*Is the background visible?*/ + if(lv_group_get_focused(g) == page) { + lv_style_t * style_mod; + style_mod = lv_group_mod_style(g, style_scrl_ori); + scrl->style_p = style_mod; /*Temporally change the style to the activated */ + } + } +#endif + ancestor_design(scrl, mask, mode); + +#if USE_LV_GROUP + scrl->style_p = style_scrl_ori; /*Revert the style*/ +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(scrl, mask, mode); + } + + return true; +} + +/** + * Signal function of the page + * @param page pointer to a page object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(page, sign, param); + if(res != LV_RES_OK) return res; + + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + lv_style_t * style = lv_obj_get_style(page); + lv_obj_t * child; + if(sign == LV_SIGNAL_CHILD_CHG) { /*Automatically move children to the scrollable object*/ + child = lv_obj_get_child(page, NULL); + while(child != NULL) { + if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) { + lv_obj_t * tmp = child; + child = lv_obj_get_child(page, child); /*Get the next child before move this*/ + lv_obj_set_parent(tmp, ext->scrl); + } else { + child = lv_obj_get_child(page, child); + } + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*If no hor_fit enabled set the scrollable's width to the page's width*/ + if(lv_cont_get_hor_fit(ext->scrl) == false) { + lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor); + } else { + ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords); + } + + /*The scrollbars are important only if they are visible now*/ + if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page); + + /*Refresh the ext. size because the scrollbars might be positioned out of the page*/ + lv_obj_refresh_ext_size(page); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*Refresh the scrollbar and notify the scrl if the size is changed*/ + if(ext->scrl != NULL && (lv_obj_get_width(page) != lv_area_get_width(param) || + lv_obj_get_height(page) != lv_area_get_height(param))) { + /*If no hor_fit enabled set the scrollable's width to the page's width*/ + if(lv_cont_get_hor_fit(ext->scrl) == false) { + lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor); + } + + ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords); + + /*The scrollbars are important only if they are visible now*/ + if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page); + } + } else if(sign == LV_SIGNAL_PRESSED) { + if(ext->pr_action != NULL) { + res = ext->pr_action(page); + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(lv_indev_is_dragging(lv_indev_get_act()) == false) { + if(ext->rel_action != NULL) { + res = ext->rel_action(page); + } + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /*Ensure ext. size for the scrollbars if they are out of the page*/ + if(page->ext_size < (-ext->sb.style->body.padding.hor)) page->ext_size = -ext->sb.style->body.padding.hor; + if(page->ext_size < (-ext->sb.style->body.padding.ver)) page->ext_size = -ext->sb.style->body.padding.ver; + } else if(sign == LV_SIGNAL_CONTROLL) { + uint32_t c = *((uint32_t *) param); + + if((c == LV_GROUP_KEY_DOWN) && ext->arrow_scroll) { + lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4); + } else if((c == LV_GROUP_KEY_UP) && ext->arrow_scroll) { + lv_page_scroll_ver(page, lv_obj_get_height(page) / 4); + } else if((c == LV_GROUP_KEY_RIGHT) && ext->arrow_scroll) { + /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/ + if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4); + else lv_page_scroll_hor(page, - lv_obj_get_width(page) / 4); + } else if((c == LV_GROUP_KEY_LEFT) && ext->arrow_scroll) { + /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/ + if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, lv_obj_get_height(page) / 4); + else lv_page_scroll_hor(page, lv_obj_get_width(page) / 4); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = lv_page_get_arrow_scroll(page); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_page"; + } + + return res; +} + +/** + * Signal function of the scrollable part of a page + * @param scrl pointer to the scrollable object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * page = lv_obj_get_parent(scrl); + lv_style_t * page_style = lv_obj_get_style(page); + lv_page_ext_t * page_ext = lv_obj_get_ext_attr(page); + + if(sign == LV_SIGNAL_CORD_CHG) { + /*Limit the position of the scrollable object to be always visible + * (Do not let its edge inner then its parent respective edge)*/ + lv_coord_t new_x = lv_obj_get_x(scrl); + lv_coord_t new_y = lv_obj_get_y(scrl); + bool refr_x = false; + bool refr_y = false; + lv_area_t page_coords; + lv_area_t scrl_coords; + lv_obj_get_coords(scrl, &scrl_coords); + lv_obj_get_coords(page, &page_coords); + + lv_area_t * ori_coords = (lv_area_t *) param; + lv_coord_t diff_x = scrl->coords.x1 - ori_coords->x1; + lv_coord_t diff_y = scrl->coords.y1 - ori_coords->y1; + lv_coord_t hpad = page_style->body.padding.hor; + lv_coord_t vpad = page_style->body.padding.ver; + lv_obj_t * page_parent = lv_obj_get_parent(page); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t drag_vect; + lv_indev_get_vect(indev, &drag_vect); + + + /* Start the scroll propagation if there is drag vector on the indev, but the drag is not started yet + * and the scrollable is in a corner. It will enable the scroll propagation only when a new scroll begins and not + * when the scrollable is already being scrolled.*/ + if(page_ext->scroll_prop && page_ext->scroll_prop_ip == 0 && lv_indev_is_dragging(indev) == false) { + if(((drag_vect.y > 0 && scrl_coords.y1 == page_coords.y1 + vpad) || + (drag_vect.y < 0 && scrl_coords.y2 == page_coords.y2 - vpad)) && + ((drag_vect.x > 0 && scrl_coords.x1 == page_coords.x1 + hpad) || + (drag_vect.x < 0 && scrl_coords.x2 == page_coords.x2 - hpad))) { + + if(lv_obj_get_parent(page_parent) != NULL) { /*Do not propagate the scroll to a screen*/ + page_ext->scroll_prop_ip = 1; + } + } + } + + /*scrollable width smaller then page width? -> align to left*/ + if(lv_area_get_width(&scrl_coords) + 2 * hpad <= lv_area_get_width(&page_coords)) { + if(scrl_coords.x1 != page_coords.x1 + hpad) { + new_x = hpad; + refr_x = true; + } + } else { + /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/ + if(page_ext->scroll_prop_ip) { + if(drag_vect.x == diff_x) { /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/ + new_x = ori_coords->x1 - page_coords.x1; + refr_x = true; + } + } + /*The edges of the scrollable can not be in the page (minus hpad) */ + else if(scrl_coords.x2 < page_coords.x2 - hpad) { + new_x = lv_area_get_width(&page_coords) - lv_area_get_width(&scrl_coords) - hpad; /* Right align */ + refr_x = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.right_ip = 1; + } + } + else if(scrl_coords.x1 > page_coords.x1 + hpad) { + new_x = hpad; /*Left align*/ + refr_x = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.left_ip = 1; + } + } + } + + /*scrollable height smaller then page height? -> align to left*/ + if(lv_area_get_height(&scrl_coords) + 2 * vpad <= lv_area_get_height(&page_coords)) { + if(scrl_coords.y1 != page_coords.y1 + vpad) { + new_y = vpad; + refr_y = true; + } + } else { + /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/ + if(page_ext->scroll_prop_ip) { + if(drag_vect.y == diff_y) { /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/ + new_y = ori_coords->y1 - page_coords.y1; + refr_y = true; + } + } + /*The edges of the scrollable can not be in the page (minus vpad) */ + else if(scrl_coords.y2 < page_coords.y2 - vpad) { + new_y = lv_area_get_height(&page_coords) - lv_area_get_height(&scrl_coords) - vpad; /* Bottom align */ + refr_y = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.bottom_ip = 1; + } + } + else if(scrl_coords.y1 > page_coords.y1 + vpad) { + new_y = vpad; /*Top align*/ + refr_y = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.top_ip = 1; + } + } + } + + if(refr_x || refr_y) { + lv_obj_set_pos(scrl, new_x, new_y); + + if(page_ext->scroll_prop_ip) { + if(refr_y) lv_obj_set_y(page_parent, lv_obj_get_y(page_parent) + diff_y); + if(refr_x) lv_obj_set_x(page_parent, lv_obj_get_x(page_parent) + diff_x); + } + } + + lv_page_sb_refresh(page); + } + else if(sign == LV_SIGNAL_DRAG_END) { + + /*Scroll propagation is finished on drag end*/ + page_ext->scroll_prop_ip = 0; + + /*Hide scrollbars if required*/ + if(page_ext->sb.mode == LV_SB_MODE_DRAG) { + lv_area_t sb_area_tmp; + if(page_ext->sb.hor_draw) { + lv_area_copy(&sb_area_tmp, &page_ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + page_ext->sb.hor_draw = 0; + } + if(page_ext->sb.ver_draw) { + lv_area_copy(&sb_area_tmp, &page_ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + page_ext->sb.ver_draw = 0; + } + } + } else if(sign == LV_SIGNAL_PRESSED) { + if(page_ext->pr_action != NULL) { + res = page_ext->pr_action(page); + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(lv_indev_is_dragging(lv_indev_get_act()) == false) { + if(page_ext->rel_action != NULL) { + res = page_ext->rel_action(page); + } + } + } + + return res; +} + + +/** + * Refresh the position and size of the scroll bars. + * @param page pointer to a page object + */ +static void lv_page_sb_refresh(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + lv_style_t * style = lv_obj_get_style(page); + lv_obj_t * scrl = ext->scrl; + lv_coord_t size_tmp; + lv_coord_t scrl_w = lv_obj_get_width(scrl); + lv_coord_t scrl_h = lv_obj_get_height(scrl); + lv_coord_t hpad = style->body.padding.hor; + lv_coord_t vpad = style->body.padding.ver; + lv_coord_t obj_w = lv_obj_get_width(page); + lv_coord_t obj_h = lv_obj_get_height(page); + + /*Always let 'scrollbar width' padding above, under, left and right to the scrollbars + * else: + * - horizontal and vertical scrollbars can overlap on the corners + * - if the page has radius the scrollbar can be out of the radius */ + lv_coord_t sb_hor_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.hor); + lv_coord_t sb_ver_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.ver); + + if(ext->sb.mode == LV_SB_MODE_OFF) return; + + if(ext->sb.mode == LV_SB_MODE_ON) { + ext->sb.hor_draw = 1; + ext->sb.ver_draw = 1; + } + + /*Invalidate the current (old) scrollbar areas*/ + lv_area_t sb_area_tmp; + if(ext->sb.hor_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + if(ext->sb.ver_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + + + if(ext->sb.mode == LV_SB_MODE_DRAG && lv_indev_is_dragging(lv_indev_get_act()) == false) { + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + return; + + } + + /*Horizontal scrollbar*/ + if(scrl_w <= obj_w - 2 * hpad) { /*Full sized scroll bar*/ + lv_area_set_width(&ext->sb.hor_area, obj_w - 2 * sb_hor_pad); + lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad, obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver); + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 0; + } else { + size_tmp = (obj_w * (obj_w - (2 * sb_hor_pad))) / (scrl_w + 2 * hpad); + if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; + lv_area_set_width(&ext->sb.hor_area, size_tmp); + + lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad + + (-(lv_obj_get_x(scrl) - hpad) * (obj_w - size_tmp - 2 * sb_hor_pad)) / + (scrl_w + 2 * hpad - obj_w), + obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver); + + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 1; + } + + /*Vertical scrollbar*/ + if(scrl_h <= obj_h - 2 * vpad) { /*Full sized scroll bar*/ + lv_area_set_height(&ext->sb.ver_area, obj_h - 2 * sb_ver_pad); + lv_area_set_pos(&ext->sb.ver_area, obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor, sb_ver_pad); + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 0; + } else { + size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + 2 * vpad); + if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; + lv_area_set_height(&ext->sb.ver_area, size_tmp); + + lv_area_set_pos(&ext->sb.ver_area, obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor, + sb_ver_pad + + (-(lv_obj_get_y(scrl) - vpad) * (obj_h - size_tmp - 2 * sb_ver_pad)) / + (scrl_h + 2 * vpad - obj_h)); + + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 1; + } + + /*Invalidate the new scrollbar areas*/ + if(ext->sb.hor_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + if(ext->sb.ver_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } +} + +#if USE_LV_ANIMATION +static void edge_flash_anim(void * page, int32_t v) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.state = v; + lv_obj_invalidate(page); +} + +static void edge_flash_anim_end(void * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.top_ip = 0; + ext->edge_flash.bottom_ip = 0; + ext->edge_flash.left_ip = 0; + ext->edge_flash.right_ip = 0; + lv_obj_invalidate(page); +} +#endif + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_page.h b/bdk/libs/lvgl/lv_objx/lv_page.h new file mode 100644 index 0000000..caed34e --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_page.h @@ -0,0 +1,402 @@ +/* + * 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 . + */ + +/** + * @file lv_page.h + * + */ + +#ifndef LV_PAGE_H +#define LV_PAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_PAGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "../lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Scrollbar modes: shows when should the scrollbars be visible*/ +enum +{ + LV_SB_MODE_OFF = 0x0, /*Never show scrollbars*/ + LV_SB_MODE_ON = 0x1, /*Always show scrollbars*/ + LV_SB_MODE_DRAG = 0x2, /*Show scrollbars when page is being dragged*/ + LV_SB_MODE_AUTO = 0x3, /*Show scrollbars when the scrollable container is large enough to be scrolled*/ + LV_SB_MODE_HIDE = 0x4, /*Hide the scroll bar temporally*/ + LV_SB_MODE_UNHIDE = 0x5, /*Unhide the previously hidden scrollbar. Recover it's type too*/ +}; +typedef uint8_t lv_sb_mode_t; + +/*Data of page*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * scrl; /*The scrollable object on the background*/ + lv_style_t *bgo; /*The scrollable object on the background*/ + lv_style_t *pr; /*The scrollable object on the background*/ + lv_action_t rel_action; /*Function to call when the page is released*/ + lv_action_t pr_action; /*Function to call when the page is pressed*/ + struct { + lv_style_t *style; /*Style of scrollbars*/ + lv_area_t hor_area; /*Horizontal scrollbar area relative to the page. (Handled by the library) */ + lv_area_t ver_area; /*Vertical scrollbar area relative to the page (Handled by the library)*/ + uint8_t hor_draw :1; /*1: horizontal scrollbar is visible now (Handled by the library)*/ + uint8_t ver_draw :1; /*1: vertical scrollbar is visible now (Handled by the library)*/ + lv_sb_mode_t mode:3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/ + } sb; + struct { + uint16_t state; /*Store the current size of the edge flash effect*/ + lv_style_t *style; /*Style of edge flash effect (usually homogeneous circle)*/ + uint8_t enabled :1; /*1: Show a flash animation on the edge*/ + uint8_t top_ip :1; /*Used internally to show that top most position is reached (flash is In Progress)*/ + uint8_t bottom_ip :1; /*Used internally to show that bottom most position is reached (flash is In Progress)*/ + uint8_t right_ip :1; /*Used internally to show that right most position is reached (flash is In Progress)*/ + uint8_t left_ip :1; /*Used internally to show that left most position is reached (flash is In Progress)*/ + }edge_flash; + + uint8_t arrow_scroll :1; /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/ + uint8_t scroll_prop :1; /*1: Propagate the scrolling the the parent if the edge is reached*/ + uint8_t scroll_prop_ip :1; /*1: Scroll propagation is in progress (used by the library)*/ +} lv_page_ext_t; + +enum { + LV_PAGE_STYLE_BG, + LV_PAGE_STYLE_BGO, + LV_PAGE_STYLE_PR, + LV_PAGE_STYLE_SCRL, + LV_PAGE_STYLE_SB, + LV_PAGE_STYLE_EDGE_FLASH, +}; +typedef uint8_t lv_page_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t *obj); + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page); + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page); + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is released + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action); + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action); + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode); + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en); + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en); + +/** + * Set the fit attribute of the scrollable part of a page. + * It means it can set its size automatically to involve all children. + * (Can be set separately horizontally and vertically) + * @param page pointer to a page object + * @param hor_en true: enable horizontal fit + * @param ver_en true: enable vertical fit + */ +static inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en); +} + +/** + * Set width of the scrollable part of a page + * @param page pointer to a page object + * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled) + */ +static inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w) +{ + lv_obj_set_width(lv_page_get_scrl(page), w); +} + +/** + * Set height of the scrollable part of a page + * @param page pointer to a page object + * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled) + */ +static inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h) +{ + lv_obj_set_height(lv_page_get_scrl(page), h); + +} + +/** +* Set the layout of the scrollable part of the page +* @param page pointer to a page object +* @param layout a layout from 'lv_cont_layout_t' +*/ +static inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout) +{ + lv_cont_set_layout(lv_page_get_scrl(page), layout); +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page); + + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page); + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page); + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page); + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page); + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page); + +/** + * Get width of the scrollable part of a page + * @param page pointer to a page object + * @return the width of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page) +{ + return lv_obj_get_width(lv_page_get_scrl(page)); +} + +/** + * Get height of the scrollable part of a page + * @param page pointer to a page object + * @return the height of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page) +{ + return lv_obj_get_height(lv_page_get_scrl(page)); +} + +/** +* Get the layout of the scrollable part of a page +* @param page pointer to page object +* @return the layout from 'lv_cont_layout_t' +*/ +static inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page) +{ + return lv_cont_get_layout(lv_page_get_scrl(page)); +} + +/** +* Get horizontal fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: horizontal fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page) +{ + return lv_cont_get_hor_fit(lv_page_get_scrl(page)); +} + +/** +* Get vertical fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: vertical fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page) +{ + return lv_cont_get_ver_fit(lv_page_get_scrl(page)); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue); + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist); + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist); + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PAGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PAGE_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_preload.c b/bdk/libs/lvgl/lv_objx/lv_preload.c new file mode 100644 index 0000000..1700a4d --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_preload.c @@ -0,0 +1,411 @@ +/** + * @file lv_preload.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_preload.h" +#if USE_LV_PRELOAD != 0 + +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_rect.h" +#include "../lv_draw/lv_draw_arc.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_PRELOAD_DEF_ARC_LENGTH +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +#endif + +#ifndef LV_PRELOAD_DEF_SPIN_TIME +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#endif + +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC /*animation type*/ +#endif + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a pre loader object + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("preload create started"); + + /*Create the ancestor of pre loader*/ + lv_obj_t * new_preload = lv_arc_create(par, copy); + lv_mem_assert(new_preload); + if(new_preload == NULL) return NULL; + + /*Allocate the pre loader type specific extended data*/ + lv_preload_ext_t * ext = lv_obj_allocate_ext_attr(new_preload, sizeof(lv_preload_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_preload); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_preload); + + /*Initialize the allocated 'ext' */ + ext->arc_length = LV_PRELOAD_DEF_ARC_LENGTH; + ext->anim_type = LV_PRELOAD_DEF_ANIM; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_preload, lv_preload_signal); + lv_obj_set_design_func(new_preload, lv_preload_design); + + + /*Init the new pre loader pre loader*/ + if(copy == NULL) { + lv_obj_set_size(new_preload, LV_DPI / 2, LV_DPI / 2); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_preload_set_style(new_preload, LV_PRELOAD_STYLE_MAIN, th->preload); + } else { + lv_obj_set_style(new_preload, &lv_style_pretty_color); + } + + ext->time = LV_PRELOAD_DEF_SPIN_TIME; + + } + /*Copy an existing pre loader*/ + else { + lv_preload_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->arc_length = copy_ext->arc_length; + ext->time = copy_ext->time; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_preload); + } + + lv_preload_set_animation_type(new_preload, ext->anim_type); + + + LV_LOG_INFO("preload created"); + + return new_preload; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + ext->arc_length = deg; +} + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + ext->time = time; + lv_preload_set_animation_type(preload, ext->anim_type); +} +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_PRELOAD_STYLE_MAIN: + lv_arc_set_style(preload, LV_ARC_STYLE_MAIN, style); + break; + } +} + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type) +{ +#if USE_LV_ANIMATION + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + /*delete previous animation*/ + //lv_anim_del(preload, NULL); + switch(type) + { + case LV_PRELOAD_TYPE_FILLSPIN_ARC: + { + ext->anim_type = LV_PRELOAD_TYPE_FILLSPIN_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 1; + a.repeat_pause = 0; + lv_anim_create(&a); + + lv_anim_t b; + b.var = preload; + b.start = ext->arc_length; + b.end = 360 - ext->arc_length; + b.fp = (lv_anim_fp_t)lv_preload_set_arc_length; + b.path = lv_anim_path_ease_in_out; + b.end_cb = NULL; + b.act_time = 0; + b.time = ext->time; + b.playback = 1; + b.playback_pause = 0; + b.repeat = 1; + b.repeat_pause = 0; + lv_anim_create(&b); + break; + } + case LV_PRELOAD_TYPE_SPINNING_ARC: + default: + { + ext->anim_type = LV_PRELOAD_TYPE_SPINNING_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 1; + a.repeat_pause = 0; + lv_anim_create(&a); + break; + } + } + +#endif //USE_LV_ANIMATION +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->arc_length; + +} + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->time; +} + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_PRELOAD_STYLE_MAIN: + style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->anim_type; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Automatically in an animation to rotate the arc of spinner. + * @param ptr pointer to preloader + * @param val the current desired value [0..360] + */ +void lv_preload_spinner_animation(void * ptr, int32_t val) +{ + lv_obj_t * preload = ptr; + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + int16_t angle_start = val - ext->arc_length / 2 + 180; + int16_t angle_end = angle_start + ext->arc_length; + + angle_start = angle_start % 360; + angle_end = angle_end % 360; + + lv_arc_set_angles(preload, angle_start, angle_end); + +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the pre loaders + * @param preload pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + /*Draw a circle as background*/ + lv_style_t * style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); + if(style->body.border.width > 0) { + lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(preload), lv_obj_get_height(preload))) / 2; + r -= LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver); + + lv_coord_t x = preload->coords.x1 + lv_obj_get_width(preload) / 2; + lv_coord_t y = preload->coords.y1 + lv_obj_get_height(preload) / 2; + + lv_style_t bg_style; + lv_style_copy(&bg_style, &lv_style_plain); + bg_style.body.empty = 1; + bg_style.body.radius = LV_RADIUS_CIRCLE; + bg_style.body.border.color = style->body.border.color; + bg_style.body.border.width = style->body.border.width; + + lv_area_t bg_area; + bg_area.x1 = x - r; + bg_area.y1 = y - r; + bg_area.x2 = x + r; + bg_area.y2 = y + r; + + lv_draw_rect(&bg_area, mask, &bg_style, lv_obj_get_opa_scale(preload)); + } + /*Draw the arc above the background circle */ + ancestor_design(preload, mask, mode); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the pre loader + * @param preload pointer to a pre loader object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(preload, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_preload"; + } + + return res; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_preload.h b/bdk/libs/lvgl/lv_objx/lv_preload.h new file mode 100644 index 0000000..4f12f02 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_preload.h @@ -0,0 +1,168 @@ +/** + * @file lv_preload.h + * + */ + +#ifndef LV_PRELOAD_H +#define LV_PRELOAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_PRELOAD != 0 + +/*Testing of dependencies*/ +#if USE_LV_ARC == 0 +#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC 1) " +#endif + +#if USE_LV_ANIMATION == 0 +#error "lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_arc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, +}; +typedef uint8_t lv_preloader_type_t; + +/*Data of pre loader*/ +typedef struct { + lv_arc_ext_t arc; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t arc_length; /*Length of the spinning indicator in degree*/ + uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ +} lv_preload_ext_t; + + +/*Styles*/ +enum { + LV_PRELOAD_STYLE_MAIN, +}; +typedef uint8_t lv_preload_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a pre loader objects + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg); + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload); + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + +/*===================== + * Other functions + *====================*/ + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +void lv_preload_spinner_animation(void * ptr, int32_t val); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PRELOAD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PRELOAD_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_roller.c b/bdk/libs/lvgl/lv_objx/lv_roller.c new file mode 100644 index 0000000..28c8b80 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_roller.c @@ -0,0 +1,582 @@ +/** + * @file lv_roller.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_roller.h" +#if USE_LV_ROLLER != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 200 /*ms*/ +# endif +#else +# undef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 0 /*No animation*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param); +static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param); +static void refr_position(lv_obj_t * roller, bool anim_en); +static void draw_bg(lv_obj_t * roller, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("roller create started"); + + /*Create the ancestor of roller*/ + lv_obj_t * new_roller = lv_ddlist_create(par, copy); + lv_mem_assert(new_roller); + if(new_roller == NULL) return NULL; + + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_roller)); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_roller); + + /*Allocate the roller type specific extended data*/ + lv_roller_ext_t * ext = lv_obj_allocate_ext_attr(new_roller, sizeof(lv_roller_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + ext->ddlist.draw_arrow = 0; /*Do not draw arrow by default*/ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_roller, lv_roller_signal); + lv_obj_set_design_func(new_roller, lv_roller_design); + + /*Init the new roller roller*/ + if(copy == NULL) { + lv_obj_t * scrl = lv_page_get_scrl(new_roller); + lv_obj_set_drag(scrl, true); /*In ddlist is might be disabled*/ + lv_page_set_rel_action(new_roller, NULL); /*Roller don't uses it (like ddlist)*/ + lv_page_set_scrl_fit(new_roller, true, false); /*Height is specified directly*/ + lv_ddlist_open(new_roller, false); + lv_ddlist_set_anim_time(new_roller, LV_ROLLER_ANIM_TIME); + lv_roller_set_visible_row_count(new_roller, 3); + lv_label_set_align(ext->ddlist.label, LV_LABEL_ALIGN_CENTER); + + lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_roller_set_style(new_roller, LV_ROLLER_STYLE_BG, th->roller.bg); + lv_roller_set_style(new_roller, LV_ROLLER_STYLE_SEL, th->roller.sel); + } else { + /*Let the ddlist's style*/ + lv_obj_refresh_style(new_roller); /*To set scrollable size automatically*/ + } + } + /*Copy an existing roller*/ + else { + lv_obj_t * scrl = lv_page_get_scrl(new_roller); + lv_ddlist_open(new_roller, false); + lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); + + lv_obj_refresh_style(new_roller); /*Refresh the style with new signal function*/ + } + + + LV_LOG_INFO("roller created"); + + + return new_roller; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left or center) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_mem_assert(ext); + if(ext->ddlist.label == NULL) return; /*Probably the roller is being deleted if the label is NULL.*/ + lv_label_set_align(ext->ddlist.label, align); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t * roller, uint16_t sel_opt, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + if(lv_roller_get_selected(roller) == sel_opt) return; + + lv_ddlist_set_selected(roller, sel_opt); + refr_position(roller, anim_en); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t * roller, uint8_t row_cnt) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + uint8_t n_line_space = (row_cnt > 1) ? row_cnt - 1 : 1; + lv_ddlist_set_fix_height(roller, lv_font_get_height(style_label->text.font) * row_cnt + style_label->text.line_space * n_line_space); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t * roller, lv_roller_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_ROLLER_STYLE_BG: + lv_obj_set_style(roller, style); + break; + case LV_ROLLER_STYLE_SEL: + lv_ddlist_set_style(roller, LV_DDLIST_STYLE_SEL, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_mem_assert(ext); + lv_mem_assert(ext->ddlist.label); + return lv_label_get_align(ext->ddlist.label); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t * roller) +{ + return lv_page_get_scrl_hor_fit(roller); +} + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t * roller, lv_roller_style_t type) +{ + switch(type) { + case LV_ROLLER_STYLE_BG: + return lv_obj_get_style(roller); + case LV_ROLLER_STYLE_SEL: + return lv_ddlist_get_style(roller, LV_DDLIST_STYLE_SEL); + default: + return NULL; + } + + /*To avoid warning*/ + return NULL; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the rollers + * @param roller pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + draw_bg(roller, mask); + + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_opa_t opa_scale = lv_obj_get_opa_scale(roller); + const lv_font_t * font = style->text.font; + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_coord_t font_h = lv_font_get_height(font); + lv_area_t rect_area; + rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2; + if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --; /*Compensate the two rounding error*/ + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = roller->coords.x1; + rect_area.x2 = roller->coords.x2; + + lv_draw_rect(&rect_area, mask, ext->ddlist.sel_style, opa_scale); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_opa_t opa_scale = lv_obj_get_opa_scale(roller); + + /*Redraw the text on the selected area with a different color*/ + lv_area_t rect_area; + rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2; + if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --; /*Compensate the two rounding error*/ + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = roller->coords.x1; + rect_area.x2 = roller->coords.x2; + lv_area_t mask_sel; + bool area_ok; + area_ok = lv_area_intersect(&mask_sel, mask, &rect_area); + if(area_ok) { + lv_style_t * sel_style = lv_roller_get_style(roller, LV_ROLLER_STYLE_SEL); + lv_style_t new_style; + lv_txt_flag_t txt_align = LV_TXT_FLAG_NONE; + + { + lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label); + + if(LV_LABEL_ALIGN_CENTER == label_align) { + txt_align |= LV_TXT_FLAG_CENTER; + } else if(LV_LABEL_ALIGN_RIGHT == label_align) { + txt_align |= LV_TXT_FLAG_RIGHT; + } + } + + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_draw_label(&ext->ddlist.label->coords, &mask_sel, &new_style, opa_scale, + lv_label_get_text(ext->ddlist.label), txt_align, NULL); + } + } + + return true; +} + +/** + * Signal function of the roller + * @param roller pointer to a roller object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param) +{ + lv_res_t res = LV_RES_OK; + + /*Don't let the drop down list to handle the control signals. It works differently*/ + if(sign != LV_SIGNAL_CONTROLL && sign != LV_SIGNAL_FOCUS && sign != LV_SIGNAL_DEFOCUS) { + /* Include the ancient signal function */ + res = ancestor_signal(roller, sign, param); + if(res != LV_RES_OK) return res; + } + + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_align_t obj_align = LV_ALIGN_IN_LEFT_MID; + if(ext->ddlist.label) { + lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label); + if(LV_LABEL_ALIGN_CENTER == label_align) obj_align = LV_ALIGN_CENTER; + else if(LV_LABEL_ALIGN_RIGHT == label_align) obj_align = LV_ALIGN_IN_RIGHT_MID; + } + + if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_set_height(lv_page_get_scrl(roller), + lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); + lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0); + lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); + refr_position(roller, false); + } else if(sign == LV_SIGNAL_CORD_CHG) { + + if(lv_obj_get_width(roller) != lv_area_get_width(param) || + lv_obj_get_height(roller) != lv_area_get_height(param)) { + + lv_ddlist_set_fix_height(roller, lv_obj_get_height(roller)); + lv_obj_set_height(lv_page_get_scrl(roller), + lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); + + lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0); + lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); + refr_position(roller, false); + } + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(roller); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigate mode revert the original value*/ + if(!editing) { + if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) { + ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori; + refr_position(roller, true); + } + } + /*Save the current state when entered to edit mode*/ + else { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; + } + } else { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; /*Save the current value. Used to revert this state if ENER wont't be pressed*/ + + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { +#if USE_LV_GROUP + /*Revert the original state*/ + if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) { + ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori; + refr_position(roller, true); + } +#endif + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + if(ext->ddlist.sel_opt_id + 1 < ext->ddlist.option_cnt) { + lv_roller_set_selected(roller, ext->ddlist.sel_opt_id + 1, true); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + if(ext->ddlist.sel_opt_id > 0) { + lv_roller_set_selected(roller, ext->ddlist.sel_opt_id - 1, true); + } + } else if(c == LV_GROUP_KEY_ENTER) { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; /*Set the entered value as default*/ + if(ext->ddlist.action) ext->ddlist.action(roller); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(roller); + bool editing = lv_group_get_editing(g); + if(editing) lv_group_set_editing(g, false); /*In edit mode go to navigate mode if an option is selected*/ +#endif + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_roller"; + } + + return res; +} + +/** + * Signal function of the scrollable part of the roller. + * @param roller_scrl ointer to the scrollable part of roller (page) + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(roller_scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_indev_t * indev = lv_indev_get_act(); + int32_t id = -1; + lv_obj_t * roller = lv_obj_get_parent(roller_scrl); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + + if(ext->ddlist.label == NULL) return LV_RES_INV; /*On delete the ddlist signal deletes the label so nothing left to do here*/ + + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + const lv_font_t * font = style_label->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + if(sign == LV_SIGNAL_DRAG_END) { + /*If dragged then align the list to there be an element in the middle*/ + lv_coord_t label_y1 = ext->ddlist.label->coords.y1 - roller->coords.y1; + lv_coord_t label_unit = font_h + style_label->text.line_space; + lv_coord_t mid = (roller->coords.y2 - roller->coords.y1) / 2; + id = (mid - label_y1 + style_label->text.line_space / 2) / label_unit; + if(id < 0) id = 0; + if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1; + ext->ddlist.sel_opt_id = id; + if(ext->ddlist.action) ext->ddlist.action(roller); + } else if(sign == LV_SIGNAL_RELEASED) { + /*If picked an option by clicking then set it*/ + if(!lv_indev_is_dragging(indev)) { + lv_point_t p; + lv_indev_get_point(indev, &p); + p.y = p.y - ext->ddlist.label->coords.y1; + id = p.y / (font_h + style_label->text.line_space); + if(id < 0) id = 0; + if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1; + ext->ddlist.sel_opt_id = id; + if(ext->ddlist.action) ext->ddlist.action(roller); + } + } + + /*Position the scrollable according to the new selected option*/ + if(id != -1) { + refr_position(roller, true); + } + + return res; +} + +/** + * Draw a rectangle which has gradient on its top and bottom + * @param roller pointer to a roller object + * @param mask pointer to the current mask (from the design function) + */ +static void draw_bg(lv_obj_t * roller, const lv_area_t * mask) +{ + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_area_t half_mask; + lv_area_t half_roller; + lv_coord_t h = lv_obj_get_height(roller); + bool union_ok; + lv_area_copy(&half_roller, &roller->coords); + + half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */ + half_roller.x2 += roller->ext_size; + half_roller.y1 -= roller->ext_size; + half_roller.y2 = roller->coords.y1 + h / 2; + + union_ok = lv_area_intersect(&half_mask, &half_roller, mask); + + half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/ + half_roller.x2 -= roller->ext_size; + half_roller.y1 += roller->ext_size; + half_roller.y2 += style->body.radius; + + if(union_ok) { + lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller)); + } + + half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */ + half_roller.x2 += roller->ext_size; + half_roller.y2 = roller->coords.y2 + roller->ext_size; + half_roller.y1 = roller->coords.y1 + h / 2; + if((h & 0x1) == 0) half_roller.y1++; /*With even height the pixels in the middle would be drawn twice*/ + + union_ok = lv_area_intersect(&half_mask, &half_roller, mask); + + half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/ + half_roller.x2 -= roller->ext_size; + half_roller.y2 -= roller->ext_size; + half_roller.y1 -= style->body.radius; + + if(union_ok) { + lv_color_t main_tmp = style->body.main_color; + lv_color_t grad_tmp = style->body.grad_color; + + style->body.main_color = grad_tmp; + style->body.grad_color = main_tmp; + lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller)); + style->body.main_color = main_tmp; + style->body.grad_color = grad_tmp; + } +} + +/** + * Refresh the position of the roller. It uses the id stored in: ext->ddlist.selected_option_id + * @param roller pointer to a roller object + * @param anim_en true: refresh with animation; false: without animation + */ +static void refr_position(lv_obj_t * roller, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_obj_t * roller_scrl = lv_page_get_scrl(roller); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + const lv_font_t * font = style_label->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_coord_t h = lv_obj_get_height(roller); + int32_t id = ext->ddlist.sel_opt_id; + lv_coord_t line_y1 = id * (font_h + style_label->text.line_space) + ext->ddlist.label->coords.y1 - roller_scrl->coords.y1; + lv_coord_t new_y = - line_y1 + (h - font_h) / 2; + + if(ext->ddlist.anim_time == 0 || anim_en == false) { + lv_obj_set_y(roller_scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = roller_scrl; + a.start = lv_obj_get_y(roller_scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->ddlist.anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_roller.h b/bdk/libs/lvgl/lv_objx/lv_roller.h new file mode 100644 index 0000000..2f1b21c --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_roller.h @@ -0,0 +1,224 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ROLLER != 0 + +/*Testing of dependencies*/ +#if USE_LV_DDLIST == 0 +#error "lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_ddlist.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of roller*/ +typedef struct { + lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_roller_ext_t; + +enum { + LV_ROLLER_STYLE_BG, + LV_ROLLER_STYLE_SEL, +}; +typedef uint8_t lv_roller_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left, right or center[default]) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align); + +/** + * Set the options on a roller + * @param roller pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +static inline void lv_roller_set_options(lv_obj_t * roller, const char * options) +{ + lv_ddlist_set_options(roller, options); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en); + +/** + * Set a function to call when a new option is chosen + * @param roller pointer to a roller + * @param action pointer to a callback function + */ +static inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action) +{ + lv_ddlist_set_action(roller, action); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt); + +/** + * Enable or disable the horizontal fit to the content + * @param roller pointer to a roller + * @param en true: enable auto fit; false: disable auto fit + */ +static inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en) +{ + lv_ddlist_set_hor_fit(roller, en); +} + +/** + * Set the open/close animation time. + * @param roller pointer to a roller object + * @param anim_time: open/close animation time [ms] + */ +static inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time) +{ + lv_ddlist_set_anim_time(roller, anim_time); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller); + +/** + * Get the options of a roller + * @param roller pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +static inline const char * lv_roller_get_options(const lv_obj_t *roller) +{ + return lv_ddlist_get_options(roller); +} + +/** + * Get the id of the selected option + * @param roller pointer to a roller object + * @return id of the selected option (0 ... number of option - 1); + */ +static inline uint16_t lv_roller_get_selected(const lv_obj_t *roller) +{ + return lv_ddlist_get_selected(roller); +} + +/** + * Get the current selected option as a string + * @param roller pointer to roller object + * @param buf pointer to an array to store the string + */ +static inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf) +{ + lv_ddlist_get_selected_str(roller, buf); +} + +/** + * Get the "option selected" callback function + * @param roller pointer to a roller + * @return pointer to the call back function + */ +static inline lv_action_t lv_roller_get_action(const lv_obj_t * roller) +{ + return lv_ddlist_get_action(roller); +} + +/** + * Get the open/close animation time. + * @param roller pointer to a roller + * @return open/close animation time [ms] + */ +static inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller) +{ + return lv_ddlist_get_anim_time(roller); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t *roller); + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ROLLER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_slider.c b/bdk/libs/lvgl/lv_objx/lv_slider.c new file mode 100644 index 0000000..eaf04e8 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_slider.c @@ -0,0 +1,520 @@ + +/** + * @file lv_slider.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_slider.h" +#if USE_LV_SLIDER != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_SLIDER_SIZE_MIN 4 /*hor. pad and ver. pad cannot make the bar or indicator smaller then this [px]*/ +#define LV_SLIDER_NOT_PRESSED INT16_MIN + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("slider create started"); + + /*Create the ancestor slider*/ + lv_obj_t * new_slider = lv_bar_create(par, copy); + lv_mem_assert(new_slider); + if(new_slider == NULL) return NULL; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_slider); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_slider); + + /*Allocate the slider type specific extended data*/ + lv_slider_ext_t * ext = lv_obj_allocate_ext_attr(new_slider, sizeof(lv_slider_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->action = NULL; + ext->drag_value = LV_SLIDER_NOT_PRESSED; + ext->style_knob = &lv_style_pretty; + ext->knob_in = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_slider, lv_slider_signal); + lv_obj_set_design_func(new_slider, lv_slider_design); + + /*Init the new slider slider*/ + if(copy == NULL) { + lv_obj_set_click(new_slider, true); + lv_obj_set_protect(new_slider, LV_PROTECT_PRESS_LOST); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_BG, th->slider.bg); + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_INDIC, th->slider.indic); + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, th->slider.knob); + } else { + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, ext->style_knob); + } + } + /*Copy an existing slider*/ + else { + lv_slider_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->style_knob = copy_ext->style_knob; + ext->action = copy_ext->action; + ext->knob_in = copy_ext->knob_in; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_slider); + } + + + LV_LOG_INFO("slider created"); + + + return new_slider; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + ext->action = action; +} + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + if(ext->knob_in == in) return; + + ext->knob_in = in == false ? 0 : 1; + lv_obj_invalidate(slider); +} + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t * slider, lv_slider_style_t type, lv_style_t * style) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + switch(type) { + case LV_SLIDER_STYLE_BG: + lv_bar_set_style(slider, LV_BAR_STYLE_BG, style); + break; + case LV_SLIDER_STYLE_INDIC: + lv_bar_set_style(slider, LV_BAR_STYLE_INDIC, style); + break; + case LV_SLIDER_STYLE_KNOB: + ext->style_knob = style; + lv_obj_refresh_ext_size(slider); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + if(ext->drag_value != LV_SLIDER_NOT_PRESSED) return ext->drag_value; + else return lv_bar_get_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->action; +} + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->drag_value == LV_SLIDER_NOT_PRESSED ? false : true; +} + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->knob_in == 0 ? false : true; +} + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t * slider, lv_slider_style_t type) +{ + lv_style_t * style = NULL; + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + switch(type) { + case LV_SLIDER_STYLE_BG: + style = lv_bar_get_style(slider, LV_BAR_STYLE_BG); + break; + case LV_SLIDER_STYLE_INDIC: + style = lv_bar_get_style(slider, LV_BAR_STYLE_INDIC); + break; + case LV_SLIDER_STYLE_KNOB: + style = ext->style_knob; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the sliders + * @param slider pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + lv_style_t * style_bg = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG); + lv_style_t * style_knob = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB); + lv_style_t * style_indic = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC); + + lv_opa_t opa_scale = lv_obj_get_opa_scale(slider); + + lv_coord_t slider_w = lv_area_get_width(&slider->coords); + lv_coord_t slider_h = lv_area_get_height(&slider->coords); + + /*Draw the bar*/ + lv_area_t area_bg; + lv_area_copy(&area_bg, &slider->coords); + + /*Be sure at least LV_SLIDER_SIZE_MIN size will remain*/ + lv_coord_t pad_ver_bg = style_bg->body.padding.ver; + lv_coord_t pad_hor_bg = style_bg->body.padding.hor; + if(pad_ver_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) { + pad_ver_bg = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + if(pad_hor_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) { + pad_hor_bg = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + + if(ext->knob_in) { /*Enable extra size if the knob is inside */ + area_bg.x1 += pad_hor_bg; + area_bg.x2 -= pad_hor_bg; + area_bg.y1 += pad_hor_bg; + area_bg.y2 -= pad_hor_bg; + } else { /*Let space only in the perpendicular directions*/ + area_bg.x1 += slider_w < slider_h ? pad_hor_bg : 0; /*Pad only for vertical slider*/ + area_bg.x2 -= slider_w < slider_h ? pad_hor_bg : 0; /*Pad only for vertical slider*/ + area_bg.y1 += slider_w > slider_h ? pad_ver_bg : 0; /*Pad only for horizontal slider*/ + area_bg.y2 -= slider_w > slider_h ? pad_ver_bg : 0; /*Pad only for horizontal slider*/ + } + + +#if USE_LV_GROUP == 0 + lv_draw_rect(&area_bg, mask, style_bg, lv_obj_get_opa_scale(slider)); +#else + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(slider)) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.border.width = 0; + lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale); + } else { + lv_draw_rect(&area_bg, mask, style_bg, opa_scale); + } +#endif + + + /*Draw the indicator*/ + lv_area_t area_indic; + lv_area_copy(&area_indic, &area_bg); + + /*Be sure at least ver pad/hor pad width indicator will remain*/ + lv_coord_t pad_ver_indic = style_indic->body.padding.ver; + lv_coord_t pad_hor_indic = style_indic->body.padding.hor; + if(pad_ver_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) { + pad_ver_indic = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + if(pad_hor_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) { + pad_hor_indic = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + + area_indic.x1 += pad_hor_indic; + area_indic.x2 -= pad_hor_indic; + area_indic.y1 += pad_ver_indic; + area_indic.y2 -= pad_ver_indic; + + + lv_coord_t cur_value = lv_slider_get_value(slider); + lv_coord_t min_value = lv_slider_get_min_value(slider); + lv_coord_t max_value = lv_slider_get_max_value(slider); + + /*If dragged draw to the drag position*/ + if(ext->drag_value != LV_SLIDER_NOT_PRESSED) cur_value = ext->drag_value; + + if(slider_w >= slider_h) { + area_indic.x2 = (int32_t)((int32_t)(lv_area_get_width(&area_indic)) * (cur_value - min_value)) / (max_value - min_value); + area_indic.x2 = area_indic.x1 + area_indic.x2 - 1; + + } else { + area_indic.y1 = (int32_t)((int32_t)(lv_area_get_height(&area_indic)) * (cur_value - min_value)) / (max_value - min_value); + area_indic.y1 = area_indic.y2 - area_indic.y1 + 1; + } + + if(cur_value != min_value) lv_draw_rect(&area_indic, mask, style_indic, opa_scale); + + /*Before the knob add the border if required*/ +#if USE_LV_GROUP + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(slider)) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.empty = 1; + style_tmp.body.shadow.width = 0; + lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale); + } +#endif + + /*Draw the knob*/ + lv_area_t knob_area; + lv_area_copy(&knob_area, &slider->coords); + + if(slider_w >= slider_h) { + if(ext->knob_in == 0) { + knob_area.x1 = area_indic.x2 - slider_h / 2; + knob_area.x2 = knob_area.x1 + slider_h - 1; + } else { + knob_area.x1 = (int32_t)((int32_t)(slider_w - slider_h - 1) * (cur_value - min_value)) / (max_value - min_value); + knob_area.x1 += slider->coords.x1; + knob_area.x2 = knob_area.x1 + slider_h - 1; + } + + knob_area.y1 = slider->coords.y1; + knob_area.y2 = slider->coords.y2; + } else { + if(ext->knob_in == 0) { + knob_area.y1 = area_indic.y1 - slider_w / 2; + knob_area.y2 = knob_area.y1 + slider_w - 1; + } else { + knob_area.y2 = (int32_t)((int32_t)(slider_h - slider_w - 1) * (cur_value - min_value)) / (max_value - min_value); + knob_area.y2 = slider->coords.y2 - knob_area.y2; + knob_area.y1 = knob_area.y2 - slider_w - 1; + } + knob_area.x1 = slider->coords.x1; + knob_area.x2 = slider->coords.x2; + + } + lv_draw_rect(&knob_area, mask, style_knob, opa_scale); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the slider + * @param slider pointer to a slider object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(slider, sign, param); + if(res != LV_RES_OK) return res; + + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + lv_point_t p; + lv_coord_t w = lv_obj_get_width(slider); + lv_coord_t h = lv_obj_get_height(slider); + + if(sign == LV_SIGNAL_PRESSED) { + ext->drag_value = lv_slider_get_value(slider); + } else if(sign == LV_SIGNAL_PRESSING) { + lv_indev_get_point(param, &p); + int16_t tmp = 0; + if(w > h) { + lv_coord_t knob_w = h; + p.x -= slider->coords.x1 + h / 2; /*Modify the point to shift with half knob (important on the start and end)*/ + tmp = (int32_t)((int32_t) p.x * (ext->bar.max_value - ext->bar.min_value + 1)) / (w - knob_w); + tmp += ext->bar.min_value; + } else { + lv_coord_t knob_h = w; + p.y -= slider->coords.y1 + w / 2; /*Modify the point to shift with half knob (important on the start and end)*/ + tmp = (int32_t)((int32_t) p.y * (ext->bar.max_value - ext->bar.min_value + 1)) / (h - knob_h); + tmp = ext->bar.max_value - tmp; /*Invert the value: smaller value means higher y*/ + } + + if(tmp < ext->bar.min_value) tmp = ext->bar.min_value; + else if(tmp > ext->bar.max_value) tmp = ext->bar.max_value; + + if(tmp != ext->drag_value) { + ext->drag_value = tmp; + lv_obj_invalidate(slider); + if(ext->action != NULL) res = ext->action(slider); + } + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + lv_slider_set_value(slider, ext->drag_value); + ext->drag_value = LV_SLIDER_NOT_PRESSED; + if(ext->action != NULL) res = ext->action(slider); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /* The knob size depends on slider size. + * During the drawing method the ext. size is used by the knob so refresh the ext. size.*/ + if(lv_obj_get_width(slider) != lv_area_get_width(param) || + lv_obj_get_height(slider) != lv_area_get_height(param)) { + slider->signal_func(slider, LV_SIGNAL_REFR_EXT_SIZE, NULL); + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG); + lv_style_t * knob_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB); + lv_coord_t shadow_w = knob_style->body.shadow.width; + if(ext->knob_in == 0) { + /* The smaller size is the knob diameter*/ + lv_coord_t x = LV_MATH_MIN(w / 2 + 1 + shadow_w, h / 2 + 1 + shadow_w); + if(slider->ext_size < x) slider->ext_size = x; + } else { + lv_coord_t pad = LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver); + if(pad < 0) pad = -pad; + if(slider->ext_size < pad) slider->ext_size = pad; + + if(slider->ext_size < shadow_w) slider->ext_size = shadow_w; + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + + ext->drag_value = LV_SLIDER_NOT_PRESSED; + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(slider); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER && c == LV_GROUP_KEY_ENTER) { + if(editing) lv_group_set_editing(g, false); + } +#endif + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + lv_slider_set_value(slider, lv_slider_get_value(slider) + 1); + if(ext->action != NULL) res = ext->action(slider); + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + lv_slider_set_value(slider, lv_slider_get_value(slider) - 1); + if(ext->action != NULL) res = ext->action(slider); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_slider"; + } + + return res; +} +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_slider.h b/bdk/libs/lvgl/lv_objx/lv_slider.h new file mode 100644 index 0000000..6336ae8 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_slider.h @@ -0,0 +1,202 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SLIDER != 0 + +/*Testing of dependencies*/ +#if USE_LV_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of slider*/ +typedef struct +{ + lv_bar_ext_t bar; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t action; /*Function to call when a new value is set*/ + lv_style_t *style_knob; /*Style of the knob*/ + int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/ + uint8_t knob_in :1; /*1: Draw the knob inside the bar*/ +} lv_slider_ext_t; + +/*Built-in styles of slider*/ +enum +{ + LV_SLIDER_STYLE_BG, + LV_SLIDER_STYLE_INDIC, + LV_SLIDER_STYLE_KNOB, +}; +typedef uint8_t lv_slider_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param slider pointer to a slider object + * @param value new value + */ +static inline void lv_slider_set_value(lv_obj_t * slider, int16_t value) +{ + lv_bar_set_value(slider, value); +} + +/** + * Set a new value with animation on a slider + * @param slider pointer to a slider object + * @param value new value + * @param anim_time animation time in milliseconds + */ +static inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time) +{ + lv_bar_set_value_anim(slider, value, anim_time); +} + +/** + * Set minimum and the maximum values of a bar + * @param slider pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max) +{ + lv_bar_set_range(slider, min, max); +} + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action); + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in); + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider); + +/** + * Get the minimum value of a slider + * @param slider pointer to a slider object + * @return the minimum value of the slider + */ +static inline int16_t lv_slider_get_min_value(const lv_obj_t * slider) +{ + return lv_bar_get_min_value(slider); +} + +/** + * Get the maximum value of a slider + * @param slider pointer to a slider object + * @return the maximum value of the slider + */ +static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) +{ + return lv_bar_get_max_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider); + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider); + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider); + + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SLIDER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_spinbox.c b/bdk/libs/lvgl/lv_objx/lv_spinbox.c new file mode 100644 index 0000000..70fac33 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_spinbox.c @@ -0,0 +1,471 @@ +/** + * @file lv_spinbox.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_spinbox.h" + +#if USE_LV_SPINBOX != 0 +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param); +static void lv_spinbox_updatevalue(lv_obj_t * spinbox); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a spinbox object + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("spinbox create started"); + + /*Create the ancestor of spinbox*/ + lv_obj_t * new_spinbox = lv_ta_create(par, copy); + lv_mem_assert(new_spinbox); + if(new_spinbox == NULL) return NULL; + + /*Allocate the spinbox type specific extended data*/ + lv_spinbox_ext_t * ext = lv_obj_allocate_ext_attr(new_spinbox, sizeof(lv_spinbox_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_spinbox); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_spinbox); + + /*Initialize the allocated 'ext'*/ + ext->ta.one_line = 1; + ext->ta.pwd_mode = 0; + ext->ta.accapted_chars = "1234567890+-. "; + + ext->value = 0; + ext->dec_point_pos = 0; + ext->digit_count = 5; + ext->digit_padding_left = 0; + ext->step = 1; + ext->range_max = 99999; + ext->range_min = -99999; + ext->value_changed_cb = NULL; + + lv_ta_set_cursor_type(new_spinbox, LV_CURSOR_BLOCK | LV_CURSOR_HIDDEN); /*hidden by default*/ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_spinbox, lv_spinbox_signal); + lv_obj_set_design_func(new_spinbox, ancestor_design); /*Leave the Text area's design function*/ + + /*Init the new spinbox spinbox*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_BG, th->spinbox.bg); + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_CURSOR, th->spinbox.cursor); + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_SB, th->spinbox.sb); + } + } + /*Copy an existing spinbox*/ + else { + lv_spinbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + lv_spinbox_set_value(new_spinbox, copy_ext->value); + lv_spinbox_set_digit_format(new_spinbox, copy_ext->digit_count, copy_ext->dec_point_pos); + lv_spinbox_set_range(new_spinbox, copy_ext->range_min, copy_ext->range_max); + lv_spinbox_set_step(new_spinbox, copy_ext->step); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_spinbox); + } + + lv_spinbox_updatevalue(new_spinbox); + + LV_LOG_INFO("spinbox created"); + + return new_spinbox; +} + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) + return; + + if(i > ext->range_max) + i = ext->range_max; + if(i < ext->range_min) + i = ext->range_min; + + ext->value = i; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) + return; + + if(digit_count > LV_SPINBOX_MAX_DIGIT_COUNT) + digit_count = LV_SPINBOX_MAX_DIGIT_COUNT; + + if(separator_position > LV_SPINBOX_MAX_DIGIT_COUNT) + separator_position = LV_SPINBOX_MAX_DIGIT_COUNT; + + ext->digit_count = digit_count; + ext->dec_point_pos = separator_position; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) return; + + ext->step = step; +} + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) return; + + ext->range_max = range_max; + ext->range_min = range_min; + + if(ext->value > ext->range_max) { + ext->value = ext->range_max; + lv_obj_invalidate(spinbox); + } + if(ext->value < ext->range_min) { + ext->value = ext->range_min; + lv_obj_invalidate(spinbox); + } +} + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + ext->value_changed_cb = cb; +} + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + ext->digit_padding_left = padding; + lv_spinbox_updatevalue(spinbox); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + return ext->value; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + int32_t new_step = ext->step / 10; + if((new_step) > 0) ext->step = new_step; + else ext->step = 1; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + int32_t step_limit; + step_limit = LV_MATH_MAX(ext->range_max, (ext->range_min < 0 ? (-ext->range_min) : ext->range_min)); + int32_t new_step = ext->step * 10; + if(new_step <= step_limit) ext->step = new_step; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + if(ext->value + ext->step <= ext->range_max) { + /*Special mode when zero crossing*/ + if((ext->value + ext->step) > 0 && ext->value < 0) ext->value = -ext->value; + ext->value += ext->step; + + } else { + ext->value = ext->range_max; + } + + if(ext->value_changed_cb != NULL) ext->value_changed_cb(spinbox, ext->value); + lv_spinbox_updatevalue(spinbox); +} + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + if(ext->value - ext->step >= ext->range_min) { + /*Special mode when zero crossing*/ + if((ext->value - ext->step) < 0 && ext->value > 0) ext->value = -ext->value; + ext->value -= ext->step; + } else { + ext->value = ext->range_min; + } + + if(ext->value_changed_cb != NULL) ext->value_changed_cb(spinbox, ext->value); + lv_spinbox_updatevalue(spinbox); +} + + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the spinbox + * @param spinbox pointer to a spinbox object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param) +{ + + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + lv_res_t res = LV_RES_OK; + + /* Include the ancient signal function */ + if(sign != LV_SIGNAL_CONTROLL) + { + res = ancestor_signal(spinbox, sign, param); + if(res != LV_RES_OK) return res; + } + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) + { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) + { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_spinbox"; + } + else if(sign == LV_SIGNAL_CONTROLL) { + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + uint32_t c = *((uint32_t *)param); /*uint32_t because can be UTF-8*/ + if(c == LV_GROUP_KEY_RIGHT) { + if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_increment(spinbox); + else lv_spinbox_step_next(spinbox); + } + else if(c == LV_GROUP_KEY_LEFT) { + if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_decrement(spinbox); + else lv_spinbox_step_previous(spinbox); + } + else if(c == LV_GROUP_KEY_UP) { + lv_spinbox_increment(spinbox); + } + else if(c == LV_GROUP_KEY_DOWN) { + lv_spinbox_decrement(spinbox); + } + else if(c == LV_GROUP_KEY_ENTER) { + + if(ext->step > 1) { + lv_spinbox_step_next(spinbox); + } else { + /*Restart from the MSB*/ + ext->step = 1; + uint32_t i; + for(i = 0; i < ext->digit_count; i++) { + int32_t new_step = ext->step * 10; + if(new_step >= ext->range_max) break; + ext->step = new_step; + } + lv_spinbox_step_previous(spinbox); + } + } + else { + lv_ta_add_char(spinbox, c); + } + } + + return res; +} + +static void lv_spinbox_updatevalue(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + char buf[LV_SPINBOX_MAX_DIGIT_COUNT + 8]; + memset(buf, 0, sizeof(buf)); + char * buf_p = buf; + + /*Add the sign*/ + (*buf_p) = ext->value >= 0 ? '+' : '-'; + buf_p++; + + int i; + /*padding left*/ + for(i = 0; i < ext->digit_padding_left; i++) { + (*buf_p) = ' '; + buf_p++; + } + + char digits[64]; + /*Convert the numbers to string (the sign is already handled so always covert positive number)*/ + lv_math_num_to_str(ext->value < 0 ? -ext->value : ext->value, digits); + + /*Add leading zeros*/ + int lz_cnt = ext->digit_count - (int)strlen(digits); + if(lz_cnt > 0) { + for(i = strlen(digits); i >= 0; i--) { + digits[i + lz_cnt] = digits[i]; + } + for(i = 0; i < lz_cnt; i++) { + digits[i] = '0'; + } + } + + int32_t intDigits; + intDigits = (ext->dec_point_pos == 0) ? ext->digit_count : ext->dec_point_pos; + + /*Add the decimal part*/ + for(i = 0; i < intDigits && digits[i] != '\0'; i++) { + (*buf_p) = digits[i]; + buf_p++; + } + + if(ext->dec_point_pos != 0) { + /*Insert the decimal point*/ + (*buf_p) = '.'; + buf_p++; + + for(/*Leave i*/ ;i < ext->digit_count && digits[i] != '\0'; i++) { + (*buf_p) = digits[i]; + buf_p++; + } + } + + /*Refresh the text*/ + lv_ta_set_text(spinbox, (char*)buf); + + + /*Set the cursor position*/ + int32_t step = ext->step; + uint8_t cur_pos = ext->digit_count; + while(step >= 10) + { + step /= 10; + cur_pos--; + } + + if(cur_pos > intDigits ) cur_pos ++; /*Skip teh decimal point*/ + + cur_pos += ext->digit_padding_left; + + lv_ta_set_cursor_pos(spinbox, cur_pos); +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_spinbox.h b/bdk/libs/lvgl/lv_objx/lv_spinbox.h new file mode 100644 index 0000000..ca57614 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_spinbox.h @@ -0,0 +1,201 @@ +/** + * @file lv_spinbox.h + * + */ + + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SPINBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_TA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_ta.h" + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 16 + +/********************** + * TYPEDEFS + **********************/ + +/*callback on value change*/ +typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value); + +/*Data of spinbox*/ +typedef struct { + lv_ta_ext_t ta; /*Ext. of ancestor*/ + /*New data for this type */ + int32_t value; + int32_t range_max; + int32_t range_min; + int32_t step; + uint16_t digit_count:4; + uint16_t dec_point_pos:4; /*if 0, there is no separator and the number is an integer*/ + uint16_t digit_padding_left:4; + lv_spinbox_value_changed_cb_t value_changed_cb; +} lv_spinbox_ext_t; + + +/*Styles*/ +enum { + LV_SPINBOX_STYLE_BG, + LV_SPINBOX_STYLE_SB, + LV_SPINBOX_STYLE_CURSOR, +}; +typedef uint8_t lv_spinbox_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spinbox objects + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a spinbox. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +static inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style) +{ + lv_ta_set_style(spinbox, type, style); +} + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step); + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max); + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb); + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a spinbox. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +static inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type) +{ + return lv_ta_get_style(spinbox, type); +} + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox); + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox); + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SPINBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPINBOX_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_sw.c b/bdk/libs/lvgl/lv_objx/lv_sw.c new file mode 100644 index 0000000..2b09354 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_sw.c @@ -0,0 +1,445 @@ +/** + * @file lv_sw.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_sw.h" + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1) " +#endif + +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param); +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("switch create started"); + + /*Create the ancestor of switch*/ + lv_obj_t * new_sw = lv_slider_create(par, copy); + lv_mem_assert(new_sw); + if(new_sw == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_sw); + + /*Allocate the switch type specific extended data*/ + lv_sw_ext_t * ext = lv_obj_allocate_ext_attr(new_sw, sizeof(lv_sw_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->changed = 0; +#if USE_LV_ANIMATION + ext->anim_time = 0; +#endif + ext->style_knob_off = ext->slider.style_knob; + ext->style_knob_on = ext->slider.style_knob; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_sw, lv_sw_signal); + + /*Init the new switch switch*/ + if(copy == NULL) { + lv_slider_set_range(new_sw, 0, 1); + lv_obj_set_size(new_sw, 2 * LV_DPI / 3, LV_DPI / 3); + lv_slider_set_knob_in(new_sw, true); + lv_slider_set_range(new_sw, 0, LV_SWITCH_SLIDER_ANIM_MAX); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_sw_set_style(new_sw, LV_SW_STYLE_BG, th->sw.bg); + lv_sw_set_style(new_sw, LV_SW_STYLE_INDIC, th->sw.indic); + lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_OFF, th->sw.knob_off); + lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_ON, th->sw.knob_on); + } else { + /*Let the slider' style*/ + } + + } + /*Copy an existing switch*/ + else { + lv_sw_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->style_knob_off = copy_ext->style_knob_off; + ext->style_knob_on = copy_ext->style_knob_on; +#if USE_LV_ANIMATION + ext->anim_time = copy_ext->anim_time; +#endif + + if(lv_sw_get_state(new_sw)) lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); + else lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); + + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_sw); + } + + LV_LOG_INFO("switch created"); + + return new_sw; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +} + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + lv_slider_set_value(sw, 0); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +} + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw) { + bool state = lv_sw_get_state(sw); + if(state) { + lv_sw_off(sw); + } + else { + lv_sw_on(sw); + } + return !state; +} + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + if(lv_sw_get_anim_time(sw) > 0)lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + else lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +} + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + if(lv_sw_get_anim_time(sw) > 0) lv_sw_anim_to_value(sw, 0); + else lv_slider_set_value(sw, 0); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +} + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw) { + bool state = lv_sw_get_state(sw); + if(state) { + lv_sw_off_anim(sw); + } + else { + lv_sw_on_anim(sw); + } + return !state; +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, lv_style_t * style) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + switch(type) { + case LV_SLIDER_STYLE_BG: + lv_slider_set_style(sw, LV_SLIDER_STYLE_BG, style); + break; + case LV_SLIDER_STYLE_INDIC: + lv_bar_set_style(sw, LV_SLIDER_STYLE_INDIC, style); + break; + case LV_SW_STYLE_KNOB_OFF: + ext->style_knob_off = style; + if(lv_sw_get_state(sw) == 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style); + break; + case LV_SW_STYLE_KNOB_ON: + ext->style_knob_on = style; + if(lv_sw_get_state(sw) != 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style); + break; + } +} + +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time) +{ +#if USE_LV_ANIMATION + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + ext->anim_time = anim_time; +#endif +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t * sw, lv_sw_style_t type) +{ + lv_style_t * style = NULL; + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + switch(type) { + case LV_SW_STYLE_BG: + style = lv_slider_get_style(sw, LV_SLIDER_STYLE_BG); + break; + case LV_SW_STYLE_INDIC: + style = lv_slider_get_style(sw, LV_SLIDER_STYLE_INDIC); + break; + case LV_SW_STYLE_KNOB_OFF: + style = ext->style_knob_off; + break; + case LV_SW_STYLE_KNOB_ON: + style = ext->style_knob_on; + break; + default: + style = NULL; + break; + } + + return style; +} + +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw) +{ + +#if USE_LV_ANIMATION + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + return ext->anim_time; +#else + return 0; +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the switch + * @param sw pointer to a switch object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + /*Save the current (old) value before slider signal modifies it*/ + int16_t old_val; + + if(sign == LV_SIGNAL_PRESSING) old_val = ext->slider.drag_value; + else old_val = lv_slider_get_value(sw); + + /*Do not let the slider to call the callback. The Switch will do it if required*/ + lv_action_t slider_action = ext->slider.action; + ext->slider.action = NULL; + + lv_res_t res; + /* Include the ancient signal function */ + res = ancestor_signal(sw, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } + else if(sign == LV_SIGNAL_PRESSED) { + + /*Save the x coordinate of the pressed point to see if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p; + lv_indev_get_point(indev, &p); + ext->start_x = p.x; + } + ext->slided = 0; + ext->changed = 0; + } + else if(sign == LV_SIGNAL_PRESSING) { + /*See if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p = {0,0}; + lv_indev_get_point(indev, &p); + if(LV_MATH_ABS(p.x - ext->start_x) > LV_INDEV_DRAG_LIMIT) ext->slided = 1; + } + + /*If didn't slide then revert the min/max value. So click without slide won't move the switch as a slider*/ + if(ext->slided == 0) { + if(lv_sw_get_state(sw)) ext->slider.drag_value = LV_SWITCH_SLIDER_ANIM_MAX; + else ext->slider.drag_value = 0; + } + + /*If explicitly changed (by slide) don't need to be toggled on release*/ + int16_t threshold = LV_SWITCH_SLIDER_ANIM_MAX / 2; + if((old_val < threshold && ext->slider.drag_value > threshold) || + (old_val > threshold && ext->slider.drag_value < threshold)) + { + ext->changed = 1; + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + if(lv_sw_get_state(sw)) { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +#if USE_LV_ANIMATION + lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); +#endif + } + else { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +#if USE_LV_ANIMATION + lv_sw_anim_to_value(sw, 0); +#endif + } + } + else if(sign == LV_SIGNAL_RELEASED) { + /*If not dragged then toggle the switch*/ + if(ext->changed == 0) { + if(lv_sw_get_state(sw)) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); + + if(slider_action != NULL) res = slider_action(sw); + } + /*If the switch was dragged then calculate the new state based on the current position*/ + else { + int16_t v = lv_slider_get_value(sw); + if(v > LV_SWITCH_SLIDER_ANIM_MAX / 2) lv_sw_on_anim(sw); + else lv_sw_off_anim(sw); + + if(slider_action != NULL) res = slider_action(sw); + } + + } else if(sign == LV_SIGNAL_CONTROLL) { + + char c = *((char *)param); + if(c == LV_GROUP_KEY_ENTER) { + if(old_val) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); + + if(slider_action) res = slider_action(sw); + } else if(c == LV_GROUP_KEY_UP || c == LV_GROUP_KEY_RIGHT) { + lv_sw_on_anim(sw); + if(slider_action) res = slider_action(sw); + } else if(c == LV_GROUP_KEY_DOWN || c == LV_GROUP_KEY_LEFT) { + lv_sw_off_anim(sw); + if(slider_action) res = slider_action(sw); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = false; /*The ancestor slider is editable the switch is not*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_sw"; + } + + /*Restore the callback*/ + if(res == LV_RES_OK) ext->slider.action = slider_action; + + return res; +} + +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value) +{ +#if USE_LV_ANIMATION + lv_anim_t a; + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + a.var = sw; + a.start = ext->slider.bar.cur_value; + a.end = value; + a.fp = (lv_anim_fp_t)lv_slider_set_value; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = lv_sw_get_anim_time(sw); + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_sw.h b/bdk/libs/lvgl/lv_objx/lv_sw.h new file mode 100644 index 0000000..28b22f7 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_sw.h @@ -0,0 +1,194 @@ +/** + * @file lv_sw.h + * + */ + +#ifndef LV_SW_H +#define LV_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1)" +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_slider.h" + +/********************* + * DEFINES + *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 + +/********************** + * TYPEDEFS + **********************/ +/*Data of switch*/ +typedef struct +{ + lv_slider_ext_t slider; /*Ext. of ancestor*/ + /*New data for this type */ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; +#if USE_LV_ANIMATION + uint16_t anim_time; /*switch animation time */ +#endif +} lv_sw_ext_t; + +enum { + LV_SW_STYLE_BG, + LV_SW_STYLE_INDIC, + LV_SW_STYLE_KNOB_OFF, + LV_SW_STYLE_KNOB_ON, +}; +typedef uint8_t lv_sw_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t *sw); + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t *sw); + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw); + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw); + +/** + * Set a function which will be called when the switch is toggled by the user + * @param sw pointer to switch object + * @param action a callback function + */ +static inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action) +{ + lv_slider_set_action(sw, action); +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style); + +#if USE_LV_ANIMATION +/** + * Set the animation time of the switch + * @param sw pointer to a switch object + * @param anim_time animation time + * @return style pointer to a style + */ +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); +#endif + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the state of a switch + * @param sw pointer to a switch object + * @return false: OFF; true: ON + */ +static inline bool lv_sw_get_state(const lv_obj_t *sw) +{ + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; +} + +/** + * Get the switch action function + * @param slider pointer to a switch object + * @return the callback function + */ +static inline lv_action_t lv_sw_get_action(const lv_obj_t * slider) +{ + return lv_slider_get_action(slider); +} + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type); + +/** + * Get the animation time of the switch + * @param sw pointer to a switch object + * @return style pointer to a style + */ +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SW_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_ta.c b/bdk/libs/lvgl/lv_objx/lv_ta.c new file mode 100644 index 0000000..e3492a0 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_ta.c @@ -0,0 +1,1365 @@ +/** + * @file lv_ta.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_ta.h" +#if USE_LV_TA != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_refr.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +/*Test configuration*/ + +#ifndef LV_TA_CURSOR_BLINK_TIME +#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#endif + +#ifndef LV_TA_PWD_SHOW_TIME +#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define LV_TA_DEF_WIDTH (2 * LV_DPI) +#define LV_TA_DEF_HEIGHT (1 * LV_DPI) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param); +static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +#if USE_LV_ANIMATION +static void cursor_blink_anim(lv_obj_t * ta, uint8_t show); +static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x); +#endif +static void pwd_char_hider(lv_obj_t * ta); +static bool char_is_accepted(lv_obj_t * ta, uint32_t c); +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res); +static void refr_cursor_area(lv_obj_t * ta); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_design_func_t scrl_design; +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t scrl_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("text area create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_ta = lv_page_create(par, copy); + lv_mem_assert(new_ta); + if(new_ta == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ta); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ta); + if(scrl_signal == NULL) scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ta)); + if(scrl_design == NULL) scrl_design = lv_obj_get_design_func(lv_page_get_scrl(new_ta)); + + /*Allocate the object type specific extended data*/ + lv_ta_ext_t * ext = lv_obj_allocate_ext_attr(new_ta, sizeof(lv_ta_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->cursor.state = 1; + ext->pwd_mode = 0; + ext->pwd_tmp = NULL; + ext->accapted_chars = NULL; + ext->max_length = 0; + ext->cursor.style = NULL; + ext->cursor.pos = 0; + ext->cursor.type = LV_CURSOR_LINE; + ext->cursor.valid_x = 0; + ext->one_line = 0; + ext->label = NULL; + + lv_obj_set_signal_func(new_ta, lv_ta_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_ta), lv_ta_scrollable_signal); + lv_obj_set_design_func(new_ta, lv_ta_design); + + /*Init the new text area object*/ + if(copy == NULL) { + ext->label = lv_label_create(new_ta, NULL); + + lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design); + + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK); + lv_label_set_text(ext->label, "Text area"); + lv_obj_set_click(ext->label, false); + lv_obj_set_size(new_ta, LV_TA_DEF_WIDTH, LV_TA_DEF_HEIGHT); + lv_ta_set_sb_mode(new_ta, LV_SB_MODE_DRAG); + lv_page_set_style(new_ta, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_ta_set_style(new_ta, LV_TA_STYLE_BG, th->ta.area); + lv_ta_set_style(new_ta, LV_TA_STYLE_SB, th->ta.sb); + } else { + lv_ta_set_style(new_ta, LV_TA_STYLE_BG, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design); + lv_ta_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->label = lv_label_create(new_ta, copy_ext->label); + ext->pwd_mode = copy_ext->pwd_mode; + ext->accapted_chars = copy_ext->accapted_chars; + ext->max_length = copy_ext->max_length; + ext->cursor.style = copy_ext->cursor.style; + ext->cursor.pos = copy_ext->cursor.pos; + ext->cursor.valid_x = copy_ext->cursor.valid_x; + ext->cursor.type = copy_ext->cursor.type; + if(copy_ext->one_line) lv_ta_set_one_line(new_ta, true); + + lv_ta_set_style(new_ta, LV_TA_STYLE_CURSOR, lv_ta_get_style(copy, LV_TA_STYLE_CURSOR)); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_ta); + } + +#if USE_LV_ANIMATION + /*Create a cursor blinker animation*/ + lv_anim_t a; + a.var = new_ta; + a.fp = (lv_anim_fp_t)cursor_blink_anim; + a.time = LV_TA_CURSOR_BLINK_TIME; + a.act_time = 0; + a.end_cb = NULL; + a.start = 1; + a.end = 0; + a.repeat = 1; + a.repeat_pause = 0; + a.playback = 1; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#endif + + LV_LOG_INFO("text area created"); + + return new_ta; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->one_line && (c == '\n' || c == '\r')) { + LV_LOG_INFO("Text area: line break ignored in one-line mode"); + return; + } + + uint32_t c_uni = lv_txt_encoded_next((const char *)&c, NULL); + + if(char_is_accepted(ta, c_uni) == false) { + LV_LOG_INFO("Character is no accepted by the text area (too long text or not in the accepted list)"); + return; + } + + /*Disable edge flash. If a new line was added it could show edge flash effect*/ + bool edge_flash_en = lv_ta_get_edge_flash(ta); + lv_ta_set_edge_flash(ta, false); + + if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ + uint32_t letter_buf[2]; + letter_buf[0] = c; + letter_buf[1] = '\0'; + + lv_label_ins_text(ext->label, ext->cursor.pos, (const char *)letter_buf); /*Insert the character*/ + + if(ext->pwd_mode != 0) { + + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 2); /*+2: the new char + \0 */ + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, (const char *)letter_buf); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } + + /*Move the cursor after the new character*/ + lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + 1); + + /*Revert the original edge flash state*/ + lv_ta_set_edge_flash(ta, edge_flash_en); +} + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ + + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c)); + } + return; + } + + /*Disable edge flash. If a new line was added it could show edge flash effect*/ + bool edge_flash_en = lv_ta_get_edge_flash(ta); + lv_ta_set_edge_flash(ta, false); + + /*Insert the text*/ + lv_label_ins_text(ext->label, ext->cursor.pos, txt); + + if(ext->pwd_mode != 0) { + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + strlen(txt) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, txt); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } + + /*Move the cursor after the new text*/ + lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + lv_txt_get_encoded_length(txt)); + + /*Revert the original edge flash state*/ + lv_ta_set_edge_flash(ta, edge_flash_en); +} + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + uint16_t cur_pos = ext->cursor.pos; + + if(cur_pos == 0) return; + + char * label_txt = lv_label_get_text(ext->label); + /*Delete a character*/ + lv_txt_cut(label_txt, ext->cursor.pos - 1, 1); + /*Refresh the label*/ + lv_label_set_text(ext->label, label_txt); + + /*Don't let 'width == 0' because cursor will not be visible*/ + if(lv_obj_get_width(ext->label) == 0) { + lv_style_t * style = lv_obj_get_style(ext->label); + lv_obj_set_width(ext->label, style->line.width); + } + + if(ext->pwd_mode != 0) { +#if LV_TXT_UTF8 == 0 + lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, 1); +#else + uint32_t byte_pos = lv_txt_encoded_get_byte_id(ext->pwd_tmp, ext->cursor.pos - 1); + lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, lv_txt_encoded_size(&label_txt[byte_pos])); +#endif + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + } + + /*Move the cursor to the place of the deleted character*/ + lv_ta_set_cursor_pos(ta, ext->cursor.pos - 1); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + lv_label_set_text(ext->label, ""); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c)); + } + } else { + lv_label_set_text(ext->label, txt); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + } + + /*Don't let 'width == 0' because the cursor will not be visible*/ + if(lv_obj_get_width(ext->label) == 0) { + lv_style_t * style = lv_obj_get_style(ext->label); + lv_obj_set_width(ext->label, lv_font_get_width(style->text.font, ' ')); + } + + if(ext->pwd_mode != 0) { + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(txt) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + strcpy(ext->pwd_tmp, txt); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } +} + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->cursor.pos == pos) return; + + uint16_t len = lv_txt_get_encoded_length(lv_label_get_text(ext->label)); + + if(pos < 0) pos = len + pos; + + if(pos > len || pos == LV_TA_CURSOR_LAST) pos = len; + + ext->cursor.pos = pos; + + /*Position the label to make the cursor visible*/ + lv_obj_t * label_par = lv_obj_get_parent(ext->label); + lv_point_t cur_pos; + lv_style_t * style = lv_obj_get_style(ta); + const lv_font_t * font_p = style->text.font; + lv_area_t label_cords; + lv_area_t ta_cords; + lv_label_get_letter_pos(ext->label, pos, &cur_pos); + lv_obj_get_coords(ta, &ta_cords); + lv_obj_get_coords(ext->label, &label_cords); + + /*Check the top*/ + lv_coord_t font_h = lv_font_get_height(font_p); + if(lv_obj_get_y(label_par) + cur_pos.y < 0) { + lv_obj_set_y(label_par, - cur_pos.y + style->body.padding.ver); + } + + /*Check the bottom*/ + if(label_cords.y1 + cur_pos.y + font_h + style->body.padding.ver > ta_cords.y2) { + lv_obj_set_y(label_par, -(cur_pos.y - lv_obj_get_height(ta) + + font_h + 2 * style->body.padding.ver)); + } + /*Check the left (use the font_h as general unit)*/ + if(lv_obj_get_x(label_par) + cur_pos.x < font_h) { + lv_obj_set_x(label_par, - cur_pos.x + font_h); + } + + /*Check the right (use the font_h as general unit)*/ + if(label_cords.x1 + cur_pos.x + font_h + style->body.padding.hor > ta_cords.x2) { + lv_obj_set_x(label_par, -(cur_pos.x - lv_obj_get_width(ta) + + font_h + 2 * style->body.padding.hor)); + } + + ext->cursor.valid_x = cur_pos.x; + +#if USE_LV_ANIMATION + /*Reset cursor blink animation*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)cursor_blink_anim; + a.time = LV_TA_CURSOR_BLINK_TIME; + a.act_time = 0; + a.end_cb = NULL; + a.start = 1; + a.end = 0; + a.repeat = 1; + a.repeat_pause = 0; + a.playback = 1; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#endif + + refr_cursor_area(ta); +} + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_ta_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->cursor.type == cur_type) return; + + ext->cursor.type = cur_type; + + refr_cursor_area(ta); +} + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->pwd_mode == en) return; + + /*Pwd mode is now enabled*/ + if(ext->pwd_mode == 0 && en != false) { + char * txt = lv_label_get_text(ext->label); + uint16_t len = strlen(txt); + ext->pwd_tmp = lv_mem_alloc(len + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + strcpy(ext->pwd_tmp, txt); + + uint16_t i; + for(i = 0; i < len; i++) { + txt[i] = '*'; /*All char to '*'*/ + } + txt[i] = '\0'; + + lv_label_set_text(ext->label, NULL); + } + /*Pwd mode is now disabled*/ + else if(ext->pwd_mode == 1 && en == false) { + lv_label_set_text(ext->label, ext->pwd_tmp); + lv_mem_free(ext->pwd_tmp); + ext->pwd_tmp = NULL; + } + + ext->pwd_mode = en == false ? 0 : 1; + + refr_cursor_area(ta); +} + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->one_line == en) return; + + if(en) { + lv_style_t * style_ta = lv_obj_get_style(ta); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(ta)); + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + + ext->one_line = 1; + lv_page_set_scrl_fit(ta, true, true); + lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2); + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_EXPAND); + lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver); + } else { + lv_style_t * style_ta = lv_obj_get_style(ta); + + ext->one_line = 0; + lv_page_set_scrl_fit(ta, false, true); + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK); + lv_obj_set_height(ta, LV_TA_DEF_HEIGHT); + lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver); + } + + refr_cursor_area(ta); +} + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_obj_t * label = lv_ta_get_label(ta); + if(!ext->one_line) { + lv_label_set_align(label, align); + } else { + /*Normal left align. Just let the text expand*/ + if(align == LV_LABEL_ALIGN_LEFT) { + lv_label_set_long_mode(label, LV_LABEL_LONG_EXPAND); + lv_page_set_scrl_fit(ta, true, false); + lv_label_set_align(label, align); + + } + /*Else use fix label width equal to the Text area width*/ + else { + lv_label_set_long_mode(label, LV_LABEL_LONG_CROP); + lv_page_set_scrl_fit(ta, false, false); + lv_page_set_scrl_width(ta, 1); /*To refresh the scrollable's width*/ + lv_label_set_align(label, align); + + lv_style_t * bg_style = lv_ta_get_style(ta, LV_TA_STYLE_BG); + lv_obj_set_width(label, lv_obj_get_width(ta) - 2 * bg_style->body.padding.hor); + } + } + + refr_cursor_area(ta); +} + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + ext->accapted_chars = list; +} + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + ext->max_length = num; +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, lv_style_t * style) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + switch(type) { + case LV_TA_STYLE_BG: + lv_page_set_style(ta, LV_PAGE_STYLE_BG, style); + break; + case LV_TA_STYLE_SB: + lv_page_set_style(ta, LV_PAGE_STYLE_SB, style); + break; + case LV_TA_STYLE_EDGE_FLASH: + lv_page_set_style(ta, LV_PAGE_STYLE_EDGE_FLASH, style); + break; + case LV_TA_STYLE_CURSOR: + ext->cursor.style = style; + lv_obj_refresh_ext_size(lv_page_get_scrl(ta)); /*Refresh ext. size because of cursor drawing*/ + refr_cursor_area(ta); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + const char * txt; + if(ext->pwd_mode == 0) { + txt = lv_label_get_text(ext->label); + } else { + txt = ext->pwd_tmp; + } + + return txt; +} + + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->label; +} + + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->cursor.pos; +} + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_ta_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->cursor.type; +} + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->pwd_mode == 0 ? false : true; +} + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->one_line == 0 ? false : true; +} + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + return ext->accapted_chars; +} + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->max_length; +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t * ta, lv_ta_style_t type) +{ + lv_style_t * style = NULL; + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + switch(type) { + case LV_TA_STYLE_BG: + style = lv_page_get_style(ta, LV_PAGE_STYLE_BG); + break; + case LV_TA_STYLE_SB: + style = lv_page_get_style(ta, LV_PAGE_STYLE_SB); + break; + case LV_TA_STYLE_EDGE_FLASH: + style = lv_page_get_style(ta, LV_PAGE_STYLE_EDGE_FLASH); + break; + case LV_TA_STYLE_CURSOR: + style = ext->cursor.style; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta) +{ + uint16_t cp = lv_ta_get_cursor_pos(ta); + cp++; + lv_ta_set_cursor_pos(ta, cp); +} + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta) +{ + uint16_t cp = lv_ta_get_cursor_pos(ta); + if(cp > 0) { + cp--; + lv_ta_set_cursor_pos(ta, cp); + } +} + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_point_t pos; + + /*Get the position of the current letter*/ + lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos); + + /*Increment the y with one line and keep the valid x*/ + lv_style_t * label_style = lv_obj_get_style(ext->label); + const lv_font_t * font_p = label_style->text.font; + lv_coord_t font_h = lv_font_get_height(font_p); + pos.y += font_h + label_style->text.line_space + 1; + pos.x = ext->cursor.valid_x; + + /*Do not go below the last line*/ + if(pos.y < lv_obj_get_height(ext->label)) { + /*Get the letter index on the new cursor position and set it*/ + uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos); + + lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x; /*Cursor position set overwrites the valid positon */ + lv_ta_set_cursor_pos(ta, new_cur_pos); + ext->cursor.valid_x = cur_valid_x_tmp; + } +} + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_point_t pos; + + /*Get the position of the current letter*/ + lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos); + + /*Decrement the y with one line and keep the valid x*/ + lv_style_t * label_style = lv_obj_get_style(ext->label); + const lv_font_t * font = label_style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + pos.y -= font_h + label_style->text.line_space - 1; + pos.x = ext->cursor.valid_x; + + + /*Get the letter index on the new cursor position and set it*/ + uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos); + lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x; /*Cursor position set overwrites the valid positon */ + lv_ta_set_cursor_pos(ta, new_cur_pos); + ext->cursor.valid_x = cur_valid_x_tmp; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the text areas + * @param ta pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW_MAIN: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return ancestor_design(ta, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the object*/ + ancestor_design(ta, mask, mode); + + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(ta, mask, mode); + } + return true; +} + + +/** + * An extended scrollable design of the page. Calls the normal design function and draws a cursor. + * @param scrl pointer to the scrollable part of the Text area + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW_MAIN: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @return return true/false, depends on 'mode' + */ +static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return scrl_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the object*/ + scrl_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_POST) { + scrl_design(scrl, mask, mode); + + /*Draw the cursor*/ + lv_obj_t * ta = lv_obj_get_parent(scrl); + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->cursor.type == LV_CURSOR_NONE || + (ext->cursor.type & LV_CURSOR_HIDDEN) || + ext->cursor.state == 0) { + return true; /*The cursor is not visible now*/ + } + + lv_style_t cur_style; + get_cursor_style(ta, &cur_style); + + const char * txt = lv_label_get_text(ext->label); + + /*Draw he cursor according to the type*/ + lv_area_t cur_area; + lv_area_copy(&cur_area, &ext->cursor.area); + + cur_area.x1 += ext->label->coords.x1; + cur_area.y1 += ext->label->coords.y1; + cur_area.x2 += ext->label->coords.x1; + cur_area.y2 += ext->label->coords.y1; + + lv_opa_t opa_scale = lv_obj_get_opa_scale(ta); + + if(ext->cursor.type == LV_CURSOR_LINE) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } else if(ext->cursor.type == LV_CURSOR_BLOCK) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + +#if LV_TXT_UTF8 == 0 + char letter_buf[2]; + letter_buf[0] = txt[ext->cursor.txt_byte_pos]; + letter_buf[1] = '\0'; +#else + char letter_buf[8] = {0}; + memcpy(letter_buf, &txt[ext->cursor.txt_byte_pos], lv_txt_encoded_size(&txt[ext->cursor.txt_byte_pos])); +#endif + cur_area.x1 += cur_style.body.padding.hor; + cur_area.y1 += cur_style.body.padding.ver; + lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, 0); + + } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { + cur_style.body.empty = 1; + if(cur_style.body.border.width == 0) cur_style.body.border.width = 1; /*Be sure the border will be drawn*/ + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } + } + + return true; +} + +/** + * Signal function of the text area + * @param ta pointer to a text area object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(ta, sign, param); + if(res != LV_RES_OK) return res; + + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->pwd_tmp != NULL) lv_mem_free(ext->pwd_tmp); + + /* (The created label will be deleted automatically) */ + } else if(sign == LV_SIGNAL_STYLE_CHG) { + if(ext->label) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_ta = lv_obj_get_style(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + if(ext->one_line) { + /*In one line mode refresh the Text Area height because 'vpad' can modify it*/ + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2); + } else { + /*In not one line mode refresh the Label width because 'hpad' can modify it*/ + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); /*Be sure the Label is in the correct position*/ + } + lv_label_set_text(ext->label, NULL); + + } + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*Set the label width according to the text area width*/ + if(ext->label) { + if(lv_obj_get_width(ta) != lv_area_get_width(param) || + lv_obj_get_height(ta) != lv_area_get_height(param)) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); + lv_label_set_text(ext->label, NULL); /*Refresh the label*/ + + refr_cursor_area(ta); + } + } + } else if(sign == LV_SIGNAL_CONTROLL) { + uint32_t c = *((uint32_t *)param); /*uint32_t because can be UTF-8*/ + if(c == LV_GROUP_KEY_RIGHT) lv_ta_cursor_right(ta); + else if(c == LV_GROUP_KEY_LEFT) lv_ta_cursor_left(ta); + else if(c == LV_GROUP_KEY_UP) lv_ta_cursor_up(ta); + else if(c == LV_GROUP_KEY_DOWN) lv_ta_cursor_down(ta); + else if(c == LV_GROUP_KEY_BACKSPACE) lv_ta_del_char(ta); + else if(c == LV_GROUP_KEY_DEL) { + uint16_t cp = lv_ta_get_cursor_pos(ta); + lv_ta_set_cursor_pos(ta, cp + 1); + if(cp != lv_ta_get_cursor_pos(ta)) lv_ta_del_char(ta); + } + else { + lv_ta_add_char(ta, c); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_ta"; + } else if(sign == LV_SIGNAL_DEFOCUS) { + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ta); + lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN); + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ta); + lv_group_t * g = lv_obj_get_group(ta); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + if(editing) lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN)); + else lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN); + } + else { + lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN)); + } +#endif + } + return res; +} + +/** + * Signal function of the scrollable part of the text area + * @param scrl pointer to scrollable part of a text area object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + lv_obj_t * ta = lv_obj_get_parent(scrl); + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /* Include the ancient signal function */ + res = scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /*Set ext. size because the cursor might be out of this object*/ + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + scrl->ext_size = LV_MATH_MAX(scrl->ext_size, style_label->text.line_space + font_h); + } +#if 0 + else if(sign == LV_SIGNAL_CORD_CHG) { + /*Set the label width according to the text area width*/ + if(ext->label) { + if(lv_obj_get_width(ta) != lv_area_get_width(param) || + lv_obj_get_height(ta) != lv_area_get_height(param)) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); + lv_label_set_text(ext->label, NULL); /*Refresh the label*/ + + refr_cursor_area(ta); + } + } + } +#endif + + return res; +} + +#if USE_LV_ANIMATION + +/** + * Called to blink the cursor + * @param ta pointer to a text area + * @param hide 1: hide the cursor, 0: show it + */ +static void cursor_blink_anim(lv_obj_t * ta, uint8_t show) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(show != ext->cursor.state) { + ext->cursor.state = show == 0 ? 0 : 1; + if(ext->cursor.type != LV_CURSOR_NONE && + (ext->cursor.type & LV_CURSOR_HIDDEN) == 0) + { + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); + } + } +} + + +/** + * Dummy function to animate char hiding in pwd mode. + * Does nothing, but a function is required in car hiding anim. + * (pwd_char_hider callback do the real job) + * @param ta unused + * @param x unused + */ +static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x) +{ + (void)ta; + (void)x; +} + +#endif + +/** + * Hide all characters (convert them to '*') + * @param ta: pointer to text area object + */ +static void pwd_char_hider(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->pwd_mode != 0) { + char * txt = lv_label_get_text(ext->label); + int16_t len = lv_txt_get_encoded_length(txt); + bool refr = false; + uint16_t i; + for(i = 0; i < len; i++) { + txt[i] = '*'; + refr = true; + } + + txt[i] = '\0'; + + if(refr != false) lv_label_set_text(ext->label, txt); + } +} + +/** + * Test an unicode character if it is accepted or not. Checks max length and accepted char list. + * @param ta pointer to a test area object + * @param c an unicode character + * @return true: accapted; false: rejected + */ +static bool char_is_accepted(lv_obj_t * ta, uint32_t c) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /*If no restriction accept it*/ + if(ext->accapted_chars == NULL && ext->max_length == 0) return true; + + /*Too many characters?*/ + if(ext->max_length > 0 && + lv_txt_get_encoded_length(lv_ta_get_text(ta)) >= ext->max_length) { + return false; + } + + /*Accepted character?*/ + if(ext->accapted_chars) { + uint32_t i = 0; + uint32_t a; + while(ext->accapted_chars[i] != '\0') { + a = lv_txt_encoded_next(ext->accapted_chars, &i); + if(a == c) return true; /*Accepted*/ + } + + return false; /*The character wasn't in the list*/ + } else { + return true; /*If the accepted char list in not specified the accept the character*/ + } + +} + +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + if(ext->cursor.style) { + lv_style_copy(style_res, ext->cursor.style); + } else { + /*If cursor style is not specified then use the modified label style */ + lv_style_copy(style_res, label_style); + lv_color_t clv_color_tmp = style_res->text.color; /*Make letter color to cursor color*/ + style_res->text.color = style_res->body.main_color; /*In block mode the letter color will be current background color*/ + style_res->body.main_color = clv_color_tmp; + style_res->body.grad_color = clv_color_tmp; + style_res->body.border.color = clv_color_tmp; + style_res->body.border.opa = LV_OPA_COVER; + style_res->body.border.width = 1; + style_res->body.shadow.width = 0; + style_res->body.radius = 0; + style_res->body.empty = 0; + style_res->body.padding.hor = 0; + style_res->body.padding.ver = 0; + style_res->line.width = 1; + style_res->body.opa = LV_OPA_COVER; + } + +} + +static void refr_cursor_area(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + lv_style_t cur_style; + get_cursor_style(ta, &cur_style); + + uint16_t cur_pos = lv_ta_get_cursor_pos(ta); + const char * txt = lv_label_get_text(ext->label); + uint32_t byte_pos; +#if LV_TXT_UTF8 != 0 + byte_pos = lv_txt_encoded_get_byte_id(txt, cur_pos); + uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL); +#else + byte_pos = cur_pos; + uint32_t letter = txt[byte_pos]; +#endif + + lv_coord_t letter_h = lv_font_get_height(label_style->text.font); + /*Set letter_w (set not 0 on non printable but valid chars)*/ + lv_coord_t letter_w; + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + + lv_point_t letter_pos; + lv_label_get_letter_pos(ext->label, cur_pos, &letter_pos); + + /*If the cursor is out of the text (most right) draw it to the next line*/ + if(letter_pos.x + ext->label->coords.x1 + letter_w > ext->label->coords.x2 && ext->one_line == 0 && lv_label_get_align(ext->label) != LV_LABEL_ALIGN_RIGHT) { + letter_pos.x = 0; + letter_pos.y += letter_h + label_style->text.line_space; + + if(letter != '\0') { + byte_pos += lv_txt_encoded_size(&txt[byte_pos]); + letter = lv_txt_encoded_next(&txt[byte_pos], NULL); + } + + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + } + + /*Save the byte position. It is required to draw `LV_CURSOR_BLOCK`*/ + ext->cursor.txt_byte_pos = byte_pos; + + /*Draw he cursor according to the type*/ + lv_area_t cur_area; + + if(ext->cursor.type == LV_CURSOR_LINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor - (cur_style.line.width >> 1) - (cur_style.line.width & 0x1); + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + (cur_style.line.width >> 1); + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_BLOCK) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + + } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver + letter_h - (cur_style.line.width >> 1); + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h + (cur_style.line.width >> 1) + (cur_style.line.width & 0x1); + } + + /*Save the new area*/ + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); + + lv_area_copy(&ext->cursor.area, &cur_area); + + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_ta.h b/bdk/libs/lvgl/lv_objx/lv_ta.h new file mode 100644 index 0000000..3227873 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_ta.h @@ -0,0 +1,390 @@ +/** + * @file lv_ta.h + * + */ + +#ifndef LV_TA_H +#define LV_TA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TA != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_CURSOR_NONE, + LV_CURSOR_LINE, + LV_CURSOR_BLOCK, + LV_CURSOR_OUTLINE, + LV_CURSOR_UNDERLINE, + LV_CURSOR_HIDDEN = 0x08, /*Or it to any value to hide the cursor temporally*/ +}; +typedef uint8_t lv_cursor_type_t; + +/*Data of text area*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * label; /*Label of the text area*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/ + uint16_t max_length; /*The max. number of characters. 0: no limit*/ + uint8_t pwd_mode :1; /*Replace characters with '*' */ + uint8_t one_line :1; /*One line mode (ignore line breaks)*/ + struct { + lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + lv_cursor_type_t type:4; /*Shape of the cursor*/ + uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ + } cursor; +} lv_ta_ext_t; + +enum { + LV_TA_STYLE_BG, + LV_TA_STYLE_SB, + LV_TA_STYLE_EDGE_FLASH, + LV_TA_STYLE_CURSOR, +}; +typedef uint8_t lv_ta_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); + + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt); + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos); + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type); + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en); + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en); + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action) +{ + lv_page_set_rel_action(ta, action); +} + +/** + * Set the scroll bar mode of a text area + * @param ta pointer to a text area object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ta, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll. + * @param ta pointer to a Text area + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en) +{ + lv_page_set_scroll_propagation(ta, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Text Area + * @param en true or false to enable/disable end flash + */ +static inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en) +{ + lv_page_set_edge_flash(ta, en); +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta); + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta); + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta); + +/** + * Get the current cursor visibility. + * @param ta pointer to a text area object + * @return true: the cursor is drawn, false: the cursor is hidden + */ +//bool lv_ta_get_cursor_show(const lv_obj_t * ta); + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta); + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta); + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta); + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline lv_action_t lv_ta_get_action(lv_obj_t * ta) +{ + return lv_page_get_rel_action(ta); +} + +/** + * Get the scroll bar mode of a text area + * @param ta pointer to a text area object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta) +{ + return lv_page_get_sb_mode(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta) +{ + return lv_page_get_scroll_propagation(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_edge_flash(lv_obj_t * ta) +{ + return lv_page_get_edge_flash(ta); +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta); + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta); + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta); + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TA_H*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TA_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_table.c b/bdk/libs/lvgl/lv_objx/lv_table.c new file mode 100644 index 0000000..c6177ed --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_table.c @@ -0,0 +1,855 @@ +/** + * @file lv_table.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_table.h" +#if USE_LV_TABLE != 0 + +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_label.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param); +static lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id); +static void refr_size(lv_obj_t * table); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_scrl_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("table create started"); + + /*Create the ancestor of table*/ + lv_obj_t * new_table = lv_obj_create(par, copy); + lv_mem_assert(new_table); + if(new_table == NULL) return NULL; + + /*Allocate the table type specific extended data*/ + lv_table_ext_t * ext = lv_obj_allocate_ext_attr(new_table, sizeof(lv_table_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_table); + if(ancestor_scrl_design == NULL) ancestor_scrl_design = lv_obj_get_design_func(new_table); + + /*Initialize the allocated 'ext' */ + ext->cell_data = NULL; + ext->cell_style[0] = &lv_style_plain; + ext->cell_style[1] = &lv_style_plain; + ext->cell_style[2] = &lv_style_plain; + ext->cell_style[3] = &lv_style_plain; + ext->col_cnt = 0; + ext->row_cnt = 0; + + uint16_t i; + for(i = 0; i < LV_TABLE_COL_MAX; i++) { + ext->col_w[i] = LV_DPI; + } + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_table, lv_table_signal); + lv_obj_set_design_func(new_table, lv_table_design); + + /*Init the new table table*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_table_set_style(new_table, LV_TABLE_STYLE_BG, th->table.bg); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL1, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL2, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL3, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL4, th->table.cell); + } else { + lv_table_set_style(new_table, LV_TABLE_STYLE_BG, &lv_style_plain_color); + } + } + /*Copy an existing table*/ + else { + lv_table_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->cell_style[0] = copy_ext->cell_style[0]; + ext->cell_style[1] = copy_ext->cell_style[1]; + ext->cell_style[2] = copy_ext->cell_style[2]; + ext->cell_style[3] = copy_ext->cell_style[3]; + ext->col_cnt = copy_ext->col_cnt; + ext->row_cnt = copy_ext->row_cnt; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_table); + } + + LV_LOG_INFO("table created"); + + return new_table; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_value: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + lv_table_cell_format_t format; + + /*Save the format byte*/ + if(ext->cell_data[cell]) { + format.format_byte = ext->cell_data[cell][0]; + } + /*Initialize the format byte*/ + else { + format.align = LV_LABEL_ALIGN_LEFT; + format.right_merge = 0; + format.type = 0; + format.crop = 0; + } + + + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ + strcpy(ext->cell_data[cell] + 1, txt); /*Leave the format byte*/ + ext->cell_data[cell][0] = format.format_byte; + refr_size(table); +} + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t old_row_cnt = ext->row_cnt; + ext->row_cnt = row_cnt; + + if(ext->row_cnt > 0 && ext->col_cnt > 0) { + ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*)); + + /*Initilize the new fields*/ + if(old_row_cnt < row_cnt) { + uint16_t old_cell_cnt = old_row_cnt * ext->col_cnt; + uint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt; + memset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0])); + } + } + else { + lv_mem_free(ext->cell_data); + ext->cell_data = NULL; + } + + refr_size(table); +} + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt) +{ + + if(col_cnt >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_cnt: too many columns. Must be < LV_TABLE_COL_MAX."); + return; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t old_col_cnt = ext->col_cnt; + ext->col_cnt = col_cnt; + + if(ext->row_cnt > 0 && ext->col_cnt > 0) { + ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*)); + /*Initilize the new fields*/ + if(old_col_cnt < col_cnt) { + uint16_t old_cell_cnt = old_col_cnt * ext->row_cnt; + uint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt; + memset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0])); + } + + } + else { + lv_mem_free(ext->cell_data); + ext->cell_data = NULL; + } + refr_size(table); +} + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w) +{ + if(col_id >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX."); + return; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + ext->col_w[col_id] = w; + refr_size(table); +} + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_align: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.align = align; + ext->cell_data[cell][0] = format.format_byte; +} + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_type: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + if(type > 0) type--; /*User gives 1,2,3,4 but easier to handle 0, 1, 2, 3*/ + if(type >= LV_TABLE_CELL_STYLE_CNT) type = LV_TABLE_CELL_STYLE_CNT - 1; + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.type = type; + ext->cell_data[cell][0] = format.format_byte; +} + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_crop: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.crop = crop; + ext->cell_data[cell][0] = format.format_byte; +} + + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_merge_right: invalid row or column"); + return; + } + + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.right_merge = en ? 1 : 0; + ext->cell_data[cell][0] = format.format_byte; + refr_size(table); +} + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + + switch(type) { + case LV_TABLE_STYLE_BG: + lv_obj_set_style(table, style); + refr_size(table); + break; + case LV_TABLE_STYLE_CELL1: + ext->cell_style[0] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL2: + ext->cell_style[1] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL3: + ext->cell_style[2] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL4: + ext->cell_style[3] = style; + refr_size(table); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_value: invalid row or column"); + return ""; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return ""; + + return &ext->cell_data[cell][1]; /*Skip the format byte*/ +} + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->row_cnt; +} + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->col_cnt; +} + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id) +{ + if(col_id >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX."); + return 0; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->col_w[col_id]; +} + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_align: invalid row or column"); + return LV_LABEL_ALIGN_LEFT; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return LV_LABEL_ALIGN_LEFT; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.align; + } +} + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_type: invalid row or column"); + return 1; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return 1; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.type + 1; /*0,1,2,3 is stored but user sees 1,2,3,4*/ + } +} + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_crop: invalid row or column"); + return false; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return false; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.crop; + } +} + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_merge_right: invalid row or column"); + return false; + } + + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return false; + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.right_merge ? true : false; + } +} + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_style_t * style = NULL; + + switch(type) { + case LV_TABLE_STYLE_BG: + style = lv_obj_get_style(table); + break; + case LV_TABLE_STYLE_CELL1: + style = ext->cell_style[0]; + break; + case LV_TABLE_STYLE_CELL2: + style = ext->cell_style[1]; + break; + case LV_TABLE_STYLE_CELL3: + style = ext->cell_style[2]; + break; + case LV_TABLE_STYLE_CELL4: + style = ext->cell_style[3]; + break; + default: + return NULL; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the tables + * @param table pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + ancestor_scrl_design(table, mask, mode); + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_style_t * bg_style = lv_obj_get_style(table); + lv_style_t * cell_style; + lv_coord_t h_row; + lv_point_t txt_size; + lv_area_t cell_area; + lv_area_t txt_area; + lv_txt_flag_t txt_flags; + lv_opa_t opa_scale = lv_obj_get_opa_scale(table); + + uint16_t col; + uint16_t row; + uint16_t cell = 0; + + cell_area.y2 = table->coords.y1 + bg_style->body.padding.ver; + for(row = 0; row < ext->row_cnt; row++) { + h_row = get_row_height(table, row); + + cell_area.y1 = cell_area.y2; + cell_area.y2 = cell_area.y1 + h_row; + + cell_area.x2 = table->coords.x1 + bg_style->body.padding.hor; + + for(col = 0; col < ext->col_cnt; col++) { + + lv_table_cell_format_t format; + if(ext->cell_data[cell]) { + format.format_byte = ext->cell_data[cell][0]; + } else { + format.right_merge = 0; + format.align = LV_LABEL_ALIGN_LEFT; + format.type = 0; + format.crop = 1; + } + + cell_style = ext->cell_style[format.type]; + cell_area.x1 = cell_area.x2; + cell_area.x2 = cell_area.x1 + ext->col_w[col]; + + uint16_t col_merge = 0; + for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) { + + if(ext->cell_data[cell + col_merge] != NULL) { + format.format_byte = ext->cell_data[cell + col_merge][0]; + if(format.right_merge) cell_area.x2 += ext->col_w[col + col_merge + 1]; + else break; + } else { + break; + } + } + + lv_draw_rect(&cell_area, mask, cell_style, opa_scale); + + if(ext->cell_data[cell]) { + txt_area.x1 = cell_area.x1 + cell_style->body.padding.hor; + txt_area.x2 = cell_area.x2 - cell_style->body.padding.hor; + txt_area.y1 = cell_area.y1 + cell_style->body.padding.ver; + txt_area.y2 = cell_area.y2 - cell_style->body.padding.ver; + /*Align the content to the middle if not cropped*/ + if(format.crop == 0) { + txt_flags = LV_TXT_FLAG_NONE; + } else { + txt_flags = LV_TXT_FLAG_EXPAND; + } + + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags); + + /*Align the content to the middle if not cropped*/ + if(format.crop == 0) { + txt_area.y1 = cell_area.y1 + h_row / 2 - txt_size.y / 2; + txt_area.y2 = cell_area.y1 + h_row / 2 + txt_size.y / 2; + } + + switch(format.align) { + default: + case LV_LABEL_ALIGN_LEFT: + txt_flags |= LV_TXT_FLAG_NONE; + break; + case LV_LABEL_ALIGN_RIGHT: + txt_flags |= LV_TXT_FLAG_RIGHT; + break; + case LV_LABEL_ALIGN_CENTER: + txt_flags |= LV_TXT_FLAG_CENTER; + break; + } + + lv_area_t label_mask; + bool label_mask_ok; + label_mask_ok = lv_area_intersect(&label_mask, mask, &cell_area); + if(label_mask_ok) { + lv_draw_label(&txt_area, &label_mask, cell_style, opa_scale, ext->cell_data[cell] + 1, txt_flags, NULL); + } + /*Draw lines after '\n's*/ + lv_point_t p1; + lv_point_t p2; + p1.x = cell_area.x1; + p2.x = cell_area.x2; + uint16_t i; + for(i = 1; ext->cell_data[cell][i] != '\0'; i++) { + if(ext->cell_data[cell][i] == '\n') { + ext->cell_data[cell][i] = '\0'; + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags); + + p1.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2; + p2.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2; + lv_draw_line(&p1, &p2, mask, cell_style, opa_scale); + + ext->cell_data[cell][i] = '\n'; + } + } + } + + cell += col_merge + 1; + col += col_merge; + } + } + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the table + * @param table pointer to a table object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(table, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Free the cell texts*/ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t cell; + for(cell = 0; cell < ext->col_cnt * ext->row_cnt; cell++) { + if(ext->cell_data[cell]) { + lv_mem_free(ext->cell_data[cell]); + ext->cell_data[cell] = NULL; + } + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_table"; + } + + return res; +} + +static void refr_size(lv_obj_t * table) +{ + lv_coord_t h = 0; + lv_coord_t w = 0; + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + + uint16_t i; + for(i= 0; i < ext->col_cnt; i++) { + w += ext->col_w[i]; + } + for(i= 0; i < ext->row_cnt; i++) { + h += get_row_height(table, i); + } + + lv_style_t * bg_style = lv_obj_get_style(table); + + w += bg_style->body.padding.hor * 2; + h += bg_style->body.padding.ver * 2; + + lv_obj_set_size(table, w + 1, h + 1); + lv_obj_invalidate(table); +} + +static lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_point_t txt_size; + lv_coord_t txt_w; + lv_style_t * cell_style; + + uint16_t row_start = row_id * ext->col_cnt; + uint16_t cell; + uint16_t col; + lv_coord_t h_max = lv_font_get_height(ext->cell_style[0]->text.font) + 2 * ext->cell_style[0]->body.padding.ver; + + for(cell = row_start, col = 0; cell < row_start + ext->col_cnt; cell++, col ++) { + if(ext->cell_data[cell] != NULL) { + + txt_w = ext->col_w[col]; + uint16_t col_merge = 0; + for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) { + + if(ext->cell_data[cell + col_merge] != NULL) { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell + col_merge][0]; + if(format.right_merge) txt_w += ext->col_w[col + col_merge + 1]; + else break; + } else { + break; + } + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + cell_style = ext->cell_style[format.type]; + + /*With text crop assume 1 line*/ + if(format.crop) { + h_max = LV_MATH_MAX(lv_font_get_height(cell_style->text.font) + 2 * cell_style->body.padding.ver, h_max); + } + /*Without text crop calculate the height of the text in the cell*/ + else { + txt_w -= 2 * cell_style->body.padding.hor; + + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, txt_w, LV_TXT_FLAG_NONE); + + h_max = LV_MATH_MAX(txt_size.y + 2 * cell_style->body.padding.ver, h_max); + cell += col_merge; + col += col_merge; + } + } + } + + return h_max; +} + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_table.h b/bdk/libs/lvgl/lv_objx/lv_table.h new file mode 100644 index 0000000..94c3575 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_table.h @@ -0,0 +1,261 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TABLE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TABLE_COL_MAX +#define LV_TABLE_COL_MAX 12 +#endif + +#define LV_TABLE_CELL_STYLE_CNT 4 +/********************** + * TYPEDEFS + **********************/ + +typedef union { + struct { + uint8_t align:2; + uint8_t right_merge:1; + uint8_t type:2; + uint8_t crop:1; + }; + uint8_t format_byte; +}lv_table_cell_format_t; + +/*Data of table*/ +typedef struct { + /*New data for this type */ + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT]; + lv_coord_t col_w[LV_TABLE_COL_MAX]; +} lv_table_ext_t; + + +/*Styles*/ +enum { + LV_TABLE_STYLE_BG, + LV_TABLE_STYLE_CELL1, + LV_TABLE_STYLE_CELL2, + LV_TABLE_STYLE_CELL3, + LV_TABLE_STYLE_CELL4, +}; +typedef uint8_t lv_table_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt); + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt); + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w); + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align); + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type); + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop); + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en); + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table); + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table); + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id); + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col); + + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_tabview.c b/bdk/libs/lvgl/lv_objx/lv_tabview.c new file mode 100644 index 0000000..00f7d55 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_tabview.c @@ -0,0 +1,909 @@ +/* + * 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 . + */ + +/** + * @file lv_tab.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_tabview.h" +#if USE_LV_TABVIEW != 0 + +#include "lv_btnm.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 300 /*Animation time of focusing to the a list element [ms] (0: no animation) */ +# endif +#else +# undef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param); +static lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param); +static lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param); + +static void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name); +static void tabview_realign(lv_obj_t * tabview); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t page_signal; +static lv_signal_func_t page_scrl_signal; +static const char * tab_def[] = {""}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("tab view create started"); + + /*Create the ancestor of tab*/ + lv_obj_t * new_tabview = lv_obj_create(par, copy); + lv_mem_assert(new_tabview); + if(new_tabview == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tabview); + + /*Allocate the tab type specific extended data*/ + lv_tabview_ext_t * ext = lv_obj_allocate_ext_attr(new_tabview, sizeof(lv_tabview_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->drag_hor = 0; + ext->draging = 0; + ext->slide_enable = 1; + ext->tab_cur = 0; + ext->point_last.x = 0; + ext->point_last.y = 0; + ext->content = NULL; + ext->indic = NULL; + ext->btns = NULL; + ext->tab_load_action = NULL; + ext->btns_pos = LV_TABVIEW_BTNS_POS_TOP; + ext->anim_time = LV_TABVIEW_ANIM_TIME; + ext->btns_hide = 0; + + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_tabview, lv_tabview_signal); + + /*Init the new tab tab*/ + if(copy == NULL) { + ext->tab_name_ptr = lv_mem_alloc(sizeof(char *)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + ext->tab_name_ptr[0] = ""; + ext->tab_cnt = 0; + + lv_obj_set_size(new_tabview, LV_HOR_RES, LV_VER_RES); + + ext->btns = lv_btnm_create(new_tabview, NULL); + lv_obj_set_height(ext->btns, 3 * LV_DPI / 4); + lv_btnm_set_map(ext->btns, tab_def); + lv_btnm_set_action(ext->btns, tab_btnm_action); + lv_btnm_set_toggle(ext->btns, true, 0); + + ext->indic = lv_obj_create(ext->btns, NULL); + lv_obj_set_width(ext->indic, LV_DPI); + lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_set_click(ext->indic, false); + + ext->content = lv_cont_create(new_tabview, NULL); + lv_cont_set_fit(ext->content, true, false); + lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T); + lv_cont_set_style(ext->content, &lv_style_transp_tight); + lv_obj_set_height(ext->content, LV_VER_RES - lv_obj_get_height(ext->btns)); + lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, th->tabview.bg); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, th->tabview.indic); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, th->tabview.btn.bg); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_REL, th->tabview.btn.rel); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_PR, th->tabview.btn.pr); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_REL, th->tabview.btn.tgl_rel); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->tabview.btn.tgl_pr); + } else { + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_transp); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color); + } + } + /*Copy an existing tab view*/ + else { + lv_tabview_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->point_last.x = 0; + ext->point_last.y = 0; + ext->btns = lv_btnm_create(new_tabview, copy_ext->btns); + ext->indic = lv_obj_create(ext->btns, copy_ext->indic); + ext->content = lv_cont_create(new_tabview, copy_ext->content); + ext->anim_time = copy_ext->anim_time; + ext->tab_load_action = copy_ext->tab_load_action; + + ext->tab_name_ptr = lv_mem_alloc(sizeof(char *)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + ext->tab_name_ptr[0] = ""; + lv_btnm_set_map(ext->btns, ext->tab_name_ptr); + + uint16_t i; + lv_obj_t * new_tab; + lv_obj_t * copy_tab; + for(i = 0; i < copy_ext->tab_cnt; i++) { + new_tab = lv_tabview_add_tab(new_tabview, copy_ext->tab_name_ptr[i]); + copy_tab = lv_tabview_get_tab(copy, i); + lv_page_set_style(new_tab, LV_PAGE_STYLE_BG, lv_page_get_style(copy_tab, LV_PAGE_STYLE_BG)); + lv_page_set_style(new_tab, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SCRL)); + lv_page_set_style(new_tab, LV_PAGE_STYLE_SB, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SB)); + } + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_tabview); + } + + + LV_LOG_INFO("tab view created"); + + return new_tabview; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + /*Create the container page*/ + lv_obj_t * h = lv_page_create(ext->content, NULL); + lv_obj_set_size(h, lv_obj_get_width(tabview), lv_obj_get_height(ext->content)); + lv_page_set_sb_mode(h, LV_SB_MODE_OFF); // Important! + lv_page_set_style(h, LV_PAGE_STYLE_BG, &lv_style_transp); + lv_page_set_style(h, LV_PAGE_STYLE_SCRL, &lv_style_transp); + + if(page_signal == NULL) page_signal = lv_obj_get_signal_func(h); + if(page_scrl_signal == NULL) page_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(h)); + lv_obj_set_signal_func(h, tabpage_signal); + lv_obj_set_signal_func(lv_page_get_scrl(h), tabpage_scrl_signal); + + /*Extend the button matrix map with the new name*/ + char * name_dm; + if((name[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) { /*If control byte presented let is*/ + name_dm = lv_mem_alloc(strlen(name) + 1); /*+1 for the the closing '\0' */ + lv_mem_assert(name_dm); + if(name_dm == NULL) return NULL; + strcpy(name_dm, name); + } else { /*Set a no long press control byte is not presented*/ + name_dm = lv_mem_alloc(strlen(name) + 2); /*+1 for the the closing '\0' and +1 for the control byte */ + lv_mem_assert(name_dm); + if(name_dm == NULL) return NULL; + name_dm[0] = '\221'; + strcpy(&name_dm[1], name); + } + + ext->tab_cnt++; + ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt + 1)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + + ext->tab_name_ptr[ext->tab_cnt - 1] = name_dm; + ext->tab_name_ptr[ext->tab_cnt] = ""; + + lv_btnm_set_map(ext->btns, ext->tab_name_ptr); + + /*Modify the indicator size*/ + lv_style_t * style_tabs = lv_obj_get_style(ext->btns); + lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) - 2 * style_tabs->body.padding.hor) / ext->tab_cnt; + lv_obj_set_width(ext->indic, indic_width); + lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + style_tabs->body.padding.inner * ext->tab_cur + style_tabs->body.padding.hor); + + /*Set the first btn as active*/ + if(ext->tab_cnt == 1) { + ext->tab_cur = 0; + lv_tabview_set_tab_act(tabview, 0, false); + tabview_realign(tabview); /*To set the proper btns height*/ + } + + return h; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + lv_style_t * style = lv_obj_get_style(ext->content); + + lv_res_t res = LV_RES_OK; + if(id >= ext->tab_cnt) id = ext->tab_cnt - 1; + if(ext->tab_load_action && id != ext->tab_cur) res = ext->tab_load_action(tabview, id); + if(res != LV_RES_OK) return; /*Prevent the tab loading*/ + + ext->tab_cur = id; + + lv_coord_t cont_x = -(lv_obj_get_width(tabview) * id + style->body.padding.inner * id + style->body.padding.hor); + if(ext->anim_time == 0 || anim_en == false) { + lv_obj_set_x(ext->content, cont_x); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = ext->content; + a.start = lv_obj_get_x(ext->content); + a.end = cont_x; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + + /*Move the indicator*/ + lv_coord_t indic_width = lv_obj_get_width(ext->indic); + lv_style_t * tabs_style = lv_obj_get_style(ext->btns); + lv_coord_t indic_x = indic_width * id + tabs_style->body.padding.inner * id + tabs_style->body.padding.hor; + + if(ext->anim_time == 0 || anim_en == false) { + lv_obj_set_x(ext->indic, indic_x); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = ext->indic; + a.start = lv_obj_get_x(ext->indic); + a.end = indic_x; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + + lv_btnm_set_toggle(ext->btns, true, ext->tab_cur); +} + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a btn is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t * tabview, lv_tabview_action_t action) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->tab_load_action = action; +} + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->slide_enable = en == false ? 0 : 1; +} + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time_ms time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + ext->anim_time = anim_time; +} + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t * tabview, lv_tabview_style_t type, lv_style_t * style) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + switch(type) { + case LV_TABVIEW_STYLE_BG: + lv_obj_set_style(tabview, style); + break; + case LV_TABVIEW_STYLE_BTN_BG: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BG, style); + tabview_realign(tabview); + break; + case LV_TABVIEW_STYLE_BTN_REL: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_REL, style); + tabview_realign(tabview); + break; + case LV_TABVIEW_STYLE_BTN_PR: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_TABVIEW_STYLE_BTN_TGL_REL: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_TABVIEW_STYLE_BTN_TGL_PR: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_TABVIEW_STYLE_INDIC: + lv_obj_set_style(ext->indic, style); + lv_obj_set_height(ext->indic, style->body.padding.inner); + tabview_realign(tabview); + break; + } +} + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tan view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t * tabview, lv_tabview_btns_pos_t btns_pos) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + ext->btns_pos = btns_pos; + tabview_realign(tabview); +} + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + ext->btns_hide = en; + tabview_realign(tabview); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active btn index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_cur; +} + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return btn count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_cnt; +} + +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the btn (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + uint16_t i = 0; + lv_obj_t * page = lv_obj_get_child_back(ext->content, NULL); + + while(page != NULL && i != id) { + i++; + page = lv_obj_get_child_back(ext->content, page); + } + + if(i == id) return page; + + return NULL; +} + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current btn load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_load_action; +} + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->slide_enable ? true : false; +} + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->anim_time; +} + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t * tabview, lv_tabview_style_t type) +{ + lv_style_t * style = NULL; + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + switch(type) { + case LV_TABVIEW_STYLE_BG: + style = lv_obj_get_style(tabview); + break; + case LV_TABVIEW_STYLE_BTN_BG: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BG); + break; + case LV_TABVIEW_STYLE_BTN_REL: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_REL); + break; + case LV_TABVIEW_STYLE_BTN_PR: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_PR); + break; + case LV_TABVIEW_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_TABVIEW_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->btns_pos; +} + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + return ext->btns_hide; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the Tab view + * @param tabview pointer to a Tab view object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(tabview, sign, param); + if(res != LV_RES_OK) return res; + + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + if(sign == LV_SIGNAL_CLEANUP) { + uint8_t i; + for(i = 0; ext->tab_name_ptr[i][0] != '\0'; i++) lv_mem_free(ext->tab_name_ptr[i]); + + lv_mem_free(ext->tab_name_ptr); + ext->tab_name_ptr = NULL; + ext->btns = NULL; /*These objects were children so they are already invalid*/ + ext->content = NULL; + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(ext->content != NULL && + (lv_obj_get_width(tabview) != lv_area_get_width(param) || + lv_obj_get_height(tabview) != lv_area_get_height(param))) { + tabview_realign(tabview); + } + } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS || sign == LV_SIGNAL_CONTROLL) { + /* The button matrix is not in a group (the tab view is in it) but it should handle the group signals. + * So propagate the related signals to the button matrix manually*/ + if(ext->btns) { + ext->btns->signal_func(ext->btns, sign, param); + } + if(sign == LV_SIGNAL_FOCUS) { + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*With ENCODER select the first button only in edit mode*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(tabview); + if(lv_group_get_editing(g)) { + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns); + btnm_ext->btn_id_pr = 0; + lv_obj_invalidate(ext->btns); + } +#endif + } else { + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns); + btnm_ext->btn_id_pr = 0; + lv_obj_invalidate(ext->btns); + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_tabview"; + } + + return res; +} + + +/** + * Signal function of a tab's page + * @param tab pointer to a tab page object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = page_signal(tab_page, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * cont = lv_obj_get_parent(tab_page); + lv_obj_t * tabview = lv_obj_get_parent(cont); + + if(lv_tabview_get_sliding(tabview) == false) return res; + + if(sign == LV_SIGNAL_PRESSED) { + tabpage_pressed_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_PRESSING) { + tabpage_pressing_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + tabpage_press_lost_handler(tabview, tab_page); + } + + return res; +} +/** + * Signal function of the tab page's scrollable object + * @param tab_scrl pointer to a tab page's scrollable object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = page_scrl_signal(tab_scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * tab_page = lv_obj_get_parent(tab_scrl); + lv_obj_t * cont = lv_obj_get_parent(tab_page); + lv_obj_t * tabview = lv_obj_get_parent(cont); + + if(lv_tabview_get_sliding(tabview) == false) return res; + + if(sign == LV_SIGNAL_PRESSED) { + tabpage_pressed_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_PRESSING) { + tabpage_pressing_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + tabpage_press_lost_handler(tabview, tab_page); + } + + return res; +} + +/** + * Called when a tab's page or scrollable object is pressed + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + (void)tabpage; + + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + lv_indev_t * indev = lv_indev_get_act(); + lv_indev_get_point(indev, &ext->point_last); +} + +/** + * Called when a tab's page or scrollable object is being pressed + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_coord_t x_diff = point_act.x - ext->point_last.x; + lv_coord_t y_diff = point_act.y - ext->point_last.y; + + if(ext->draging == 0) { + if(x_diff >= LV_INDEV_DRAG_LIMIT || x_diff <= -LV_INDEV_DRAG_LIMIT) { + ext->drag_hor = 1; + ext->draging = 1; + lv_obj_set_drag(lv_page_get_scrl(tabpage), false); + } else if(y_diff >= LV_INDEV_DRAG_LIMIT || y_diff <= -LV_INDEV_DRAG_LIMIT) { + ext->drag_hor = 0; + ext->draging = 1; + } + } + if(ext->drag_hor) { + lv_obj_set_x(ext->content, lv_obj_get_x(ext->content) + point_act.x - ext->point_last.x); + ext->point_last.x = point_act.x; + ext->point_last.y = point_act.y; + + /*Move the indicator*/ + lv_coord_t indic_width = lv_obj_get_width(ext->indic); + lv_style_t * tabs_style = lv_obj_get_style(ext->btns); + lv_style_t * indic_style = lv_obj_get_style(ext->indic); + lv_coord_t p = ((tabpage->coords.x1 - tabview->coords.x1) * (indic_width + tabs_style->body.padding.inner)) / lv_obj_get_width(tabview); + + lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + tabs_style->body.padding.inner * ext->tab_cur + indic_style->body.padding.hor - p); + } +} + +/** + * Called when a tab's page or scrollable object is released or the press id lost + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->drag_hor = 0; + ext->draging = 0; + + lv_obj_set_drag(lv_page_get_scrl(tabpage), true); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t x_predict = 0; + + while(vect.x != 0) { + x_predict += vect.x; + vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + lv_coord_t page_x1 = tabpage->coords.x1 - tabview->coords.x1 + x_predict; + lv_coord_t page_x2 = page_x1 + lv_obj_get_width(tabpage); + lv_coord_t treshold = lv_obj_get_width(tabview) / 2; + + uint16_t tab_cur = ext->tab_cur; + if(page_x1 > treshold) { + if(tab_cur != 0) tab_cur--; + } else if(page_x2 < treshold) { + if(tab_cur < ext->tab_cnt - 1) tab_cur++; + } + + lv_tabview_set_tab_act(tabview, tab_cur, true); +} + +/** + * Called when a tab button is released + * @param tab_btnm pointer to the tab's button matrix object + * @param id the id of the tab (>= 0) + * @return LV_ACTION_RES_OK because the button matrix in not deleted in the function + */ +static lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name) +{ + lv_obj_t * tab = lv_obj_get_parent(tab_btnm); + const char ** tabs_map = lv_btnm_get_map(tab_btnm); + + uint8_t i = 0; + + while(tabs_map[i][0] != '\0') { + if(strcmp(&tabs_map[i][1], tab_name) == 0) break; /*[1] to skip the control byte*/ + i++; + } + + lv_tabview_set_tab_act(tab, i, true); + + return LV_RES_OK; +} + +/** + * Realign and resize the elements of Tab view + * @param tabview pointer to a Tab view object + */ +static void tabview_realign(lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + lv_obj_set_width(ext->btns, lv_obj_get_width(tabview)); + + if(ext->btns_hide) { + lv_obj_set_hidden(ext->btns, true); + lv_obj_set_hidden(ext->indic, true); + lv_obj_set_height(ext->content, lv_obj_get_height(tabview)); + lv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + } + else if(ext->tab_cnt != 0) { + lv_obj_set_hidden(ext->btns, false); + lv_obj_set_hidden(ext->indic, false); + + lv_style_t * style_btn_bg = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_BG); + lv_style_t * style_btn_rel = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_REL); + + /*Set the indicator widths*/ + lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_btn_bg->body.padding.inner * (ext->tab_cnt - 1) - + 2 * style_btn_bg->body.padding.hor) / ext->tab_cnt; + lv_obj_set_width(ext->indic, indic_width); + + /*Set the tabs height*/ + lv_coord_t btns_height = lv_font_get_height(style_btn_rel->text.font) + + 2 * style_btn_rel->body.padding.ver + + 2 * style_btn_bg->body.padding.ver; + lv_obj_set_height(ext->btns, btns_height); + + lv_obj_set_height(ext->content, lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns)); + + switch(ext->btns_pos) { + case LV_TABVIEW_BTNS_POS_TOP: + lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + break; + case LV_TABVIEW_BTNS_POS_BOTTOM: + lv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(ext->btns, ext->content, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + break; + } + } + + lv_obj_t * pages = lv_obj_get_child(ext->content, NULL); + while(pages != NULL) { + if(lv_obj_get_signal_func(pages) == tabpage_signal) { /*Be sure adjust only the pages (user can other things)*/ + lv_obj_set_size(pages, lv_obj_get_width(tabview), lv_obj_get_height(ext->content)); + } + pages = lv_obj_get_child(ext->content, pages); + } + + if(!ext->btns_hide) { + lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + } + + lv_tabview_set_tab_act(tabview, ext->tab_cur, false); +} +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_tabview.h b/bdk/libs/lvgl/lv_objx/lv_tabview.h new file mode 100644 index 0000000..2d60c3c --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_tabview.h @@ -0,0 +1,252 @@ +/** + * @file lv_tabview.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TABVIEW != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_PAGE == 0 +#error "lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_win.h" +#include "../lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* parametes: pointer to a tabview object, tab_id + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t); + + +enum { + LV_TABVIEW_BTNS_POS_TOP, + LV_TABVIEW_BTNS_POS_BOTTOM, +}; +typedef uint8_t lv_tabview_btns_pos_t; + +/*Data of tab*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * btns; + lv_obj_t * indic; + lv_obj_t * content; /*A rectangle to show the current tab*/ + const char ** tab_name_ptr; + lv_point_t point_last; + uint16_t tab_cur; + uint16_t tab_cnt; + uint16_t anim_time; + uint8_t slide_enable :1; /*1: enable horizontal sliding by touch pad*/ + uint8_t draging :1; + uint8_t drag_hor :1; + uint8_t btns_hide :1; + lv_tabview_btns_pos_t btns_pos :1; + lv_tabview_action_t tab_load_action; +} lv_tabview_ext_t; + +enum { + LV_TABVIEW_STYLE_BG, + LV_TABVIEW_STYLE_INDIC, + LV_TABVIEW_STYLE_BTN_BG, + LV_TABVIEW_STYLE_BTN_REL, + LV_TABVIEW_STYLE_BTN_PR, + LV_TABVIEW_STYLE_BTN_TGL_REL, + LV_TABVIEW_STYLE_BTN_TGL_PR, +}; +typedef uint8_t lv_tabview_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en); + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a tab is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action); + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en); + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time); + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style); + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tab view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos); + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active tab index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview); + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return tab count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview); +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the tab (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id); + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current tab load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview); + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview); + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview); + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type); + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview); + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_tileview.c b/bdk/libs/lvgl/lv_objx/lv_tileview.c new file mode 100644 index 0000000..7435a9b --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_tileview.c @@ -0,0 +1,578 @@ +/** + * @file lv_tileview.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_tileview.h" +#if USE_LV_TILEVIEW != 0 + +#include "lv_cont.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 300 /*Animation time loading a tile [ms] (0: no animation) */ +# endif +#else +# undef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param); +static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +static lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param); +static void drag_end_handler(lv_obj_t * tileview); +static bool set_valid_drag_dirs(lv_obj_t * tileview); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a tileview object + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("tileview create started"); + + /*Create the ancestor of tileview*/ + lv_obj_t * new_tileview = lv_page_create(par, copy); + lv_mem_assert(new_tileview); + if(new_tileview == NULL) return NULL; + + /*Allocate the tileview type specific extended data*/ + lv_tileview_ext_t * ext = lv_obj_allocate_ext_attr(new_tileview, sizeof(lv_tileview_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tileview); + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_tileview)); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_tileview); + + /*Initialize the allocated 'ext' */ + ext->anim_time = LV_TILEVIEW_ANIM_TIME; + ext->action = NULL; + ext->act_id.x = 0; + ext->act_id.y = 0; + ext->valid_pos = NULL; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_tileview, lv_tileview_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_tileview), lv_tileview_scrl_signal); + + /*Init the new tileview*/ + if(copy == NULL) { + lv_obj_set_size(new_tileview, LV_HOR_RES, LV_VER_RES); + lv_obj_set_drag_throw(lv_page_get_scrl(new_tileview), false); + lv_page_set_scrl_fit(new_tileview, true, true); + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, th->tileview.bg); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, th->tileview.scrl); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SB, th->tileview.sb); + } else { + lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, &lv_style_transp_tight); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + } + } + /*Copy an existing tileview*/ + else { + lv_tileview_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->act_id.x = copy_ext->act_id.x; + ext->act_id.y = copy_ext->act_id.y; + ext->action = copy_ext->action; + ext->anim_time = copy_ext->anim_time; + + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_tileview); + } + + LV_LOG_INFO("tileview created"); + + return new_tileview; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element) +{ + lv_obj_set_free_ptr(element, lv_obj_get_signal_func(element)); + lv_obj_set_signal_func(element, element_signal_func); + lv_obj_set_drag_parent(element, true); +} + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->valid_pos = valid_pos; +} + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + + + uint16_t i; + bool valid = false; + for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) { + if(ext->valid_pos[i].x == x && ext->valid_pos[i].y == y) { + valid = true; + } + } + + if(valid == false) return; /*Don't load not valid tiles*/ + + lv_res_t res = LV_RES_OK; + if(ext->action) res = ext->action(tileview, x, y); + if(res != LV_RES_OK) return; /*Prevent the tile loading*/ + + ext->act_id.x = x; + ext->act_id.y = y; + + lv_coord_t x_coord = -x * lv_obj_get_width(tileview); + lv_coord_t y_coord = -y * lv_obj_get_height(tileview); + lv_obj_t * scrl = lv_page_get_scrl(tileview); + if(anim_en) { +#if USE_LV_ANIMATION + lv_coord_t x_act = lv_obj_get_x(scrl); + lv_coord_t y_act = lv_obj_get_y(scrl); + + lv_anim_t a; + a.var = scrl; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + if(x_coord != x_act) { + a.start = x_act; + a.end = x_coord; + lv_anim_create(&a); + } + + if(y_coord != y_act) { + a.start = y_act; + a.end = y_coord; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + lv_anim_create(&a); + } +#endif + } else { + lv_obj_set_pos(scrl, x_coord, y_coord); + } +} + +void lv_tileview_set_tile_load_action(lv_obj_t * tileview, lv_tileview_action_t action) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->action = action; + +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t * style) +{ + + switch(type) { + case LV_TILEVIEW_STYLE_BG: + lv_obj_set_style(tileview, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/* + * New object specific "get" functions come here + */ + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type) +{ + lv_style_t * style = NULL; + switch(type) { + case LV_TILEVIEW_STYLE_BG: + style = lv_obj_get_style(tileview); + break; + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the tileview + * @param tileview pointer to a tileview object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(tileview, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_tileview"; + } + + return res; +} + +/** + * Signal function of the tileview scrollable + * @param tileview pointer to the scrollable part of the tileview object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * tileview = lv_obj_get_parent(scrl); + lv_style_t * style_bg = lv_tileview_get_style(tileview, LV_TILEVIEW_STYLE_BG); + + + /*Apply constraint on moving of the tileview*/ + if(sign == LV_SIGNAL_CORD_CHG) { + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + + /*Set horizontal drag constraint if no vertical constraint an dragged to valid x direction */ + if(ext->drag_ver == 0 && + ((ext->drag_right_en && indev->proc.drag_sum.x <= -LV_INDEV_DRAG_LIMIT) || + (ext->drag_left_en && indev->proc.drag_sum.x >= LV_INDEV_DRAG_LIMIT))) { + ext->drag_hor = 1; + } + /*Set vertical drag constraint if no horizontal constraint an dragged to valid y direction */ + if(ext->drag_hor == 0 && + ((ext->drag_bottom_en && indev->proc.drag_sum.y <= -LV_INDEV_DRAG_LIMIT) || + (ext->drag_top_en && indev->proc.drag_sum.y >= LV_INDEV_DRAG_LIMIT))) { + ext->drag_ver = 1; + } + + if(ext->drag_hor) { + ext->page.edge_flash.top_ip = 0; + ext->page.edge_flash.bottom_ip = 0; + } + + if(ext->drag_ver) { + ext->page.edge_flash.right_ip = 0; + ext->page.edge_flash.left_ip = 0; + } + + lv_coord_t x = lv_obj_get_x(scrl); + lv_coord_t y = lv_obj_get_y(scrl); + lv_coord_t h = lv_obj_get_height(tileview); + lv_coord_t w = lv_obj_get_width(tileview); + if(ext->drag_top_en == 0) { + if(y > -(ext->act_id.y * h) && indev->proc.vect.y > 0 && ext->drag_hor == 0) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.top_ip = 1; + lv_page_start_edge_flash(tileview); + } + + lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver); + } + } + if(ext->drag_bottom_en == 0 && indev->proc.vect.y < 0 && ext->drag_hor == 0) { + if(y < -(ext->act_id.y * h)) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.bottom_ip = 1; + lv_page_start_edge_flash(tileview); + } + } + + lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver); + } + if(ext->drag_left_en == 0) { + if(x > -(ext->act_id.x * w) && indev->proc.vect.x > 0 && ext->drag_ver == 0) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.left_ip = 1; + lv_page_start_edge_flash(tileview); + } + + lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor); + } + } + if(ext->drag_right_en == 0 && indev->proc.vect.x < 0 && ext->drag_ver == 0) { + if(x < -(ext->act_id.x * w)) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.right_ip = 1; + lv_page_start_edge_flash(tileview); + } + } + + lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor); + } + + /*Apply the drag constraints*/ + if(ext->drag_ver == 0) lv_obj_set_y(scrl, - ext->act_id.y * lv_obj_get_height(tileview) + style_bg->body.padding.ver); + if(ext->drag_hor == 0) lv_obj_set_x(scrl, - ext->act_id.x * lv_obj_get_width(tileview) + style_bg->body.padding.hor); + } + } + + return res; + +} + +/** + * This function is applied called for the elements of the tileview. Used when the element is + * @param element + * @param sign + * @param param + * @return + */ +static lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + lv_signal_func_t sign_func = lv_obj_get_free_ptr(element); + res = sign_func(element, sign, param); + if(res != LV_RES_OK) return res; + + /*Initialize some variables on PRESS*/ + if(sign == LV_SIGNAL_PRESSED) { + /*Get the tileview from the element*/ + lv_obj_t * tileview = lv_obj_get_parent(element); + while(tileview) { + if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview); + else break; + } + + if(tileview) { + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->drag_hor = 0; + ext->drag_ver = 0; + set_valid_drag_dirs(tileview); + } + } + + /*Animate the tabview to the correct location on RELEASE*/ + else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED) { + + /*Get the tileview from the element*/ + lv_obj_t * tileview = lv_obj_get_parent(element); + while(tileview) { + if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview); + else break; + } + + if(tileview) { + /* If the element was dragged and it moved the tileview finish the drag manually to + * let the tileview to finish the move.*/ + lv_indev_t * indev = lv_indev_get_act(); + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + if(indev->proc.drag_in_prog && (ext->drag_hor || ext->drag_ver)) { + + lv_obj_t * drag_obj = element; + while(lv_obj_get_drag_parent(drag_obj)) { + drag_obj = lv_obj_get_parent(drag_obj); + if(drag_obj == NULL) break; + } + indev->proc.drag_in_prog = 0; + if(drag_obj) drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, NULL); + } + + drag_end_handler(tileview); + } + } + + return res; +} + +/** + * Called when the user releases an element of the tileview after dragging it. + * @param tileview pointer to a tileview object + */ +static void drag_end_handler(lv_obj_t * tileview) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_obj_t * scrl = lv_page_get_scrl(tileview); + lv_point_t p; + + p.x = - (scrl->coords.x1 - LV_HOR_RES / 2); + p.y = - (scrl->coords.y1 - LV_VER_RES / 2); + + /*From the drag vector (drag throw) predict the end position*/ + if(ext->drag_hor) { + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t predict = 0; + + while(vect.x != 0) { + predict += vect.x; + vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + p.x -= predict; + } + else if(ext->drag_ver) { + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t predict = 0; + + while(vect.y != 0) { + predict += vect.y; + vect.y = vect.y * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + p.y -= predict; + } + + /*Get the index of the tile*/ + p.x = p.x / lv_obj_get_width(tileview); + p.y = p.y / lv_obj_get_height(tileview); + + /*Max +- move*/ + lv_coord_t x_move = p.x - ext->act_id.x; + lv_coord_t y_move = p.y - ext->act_id.y; + if(x_move < -1) x_move = -1; + if(x_move > 1) x_move = 1; + if(y_move < -1) y_move = -1; + if(y_move > 1) y_move = 1; + + /*Set the new tile*/ + lv_tileview_set_tile_act(tileview, ext->act_id.x + x_move, ext->act_id.y + y_move,true); +} + +static bool set_valid_drag_dirs(lv_obj_t * tileview) +{ + + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + if(ext->valid_pos == NULL) return false; + + ext->drag_bottom_en = 0; + ext->drag_top_en = 0; + ext->drag_left_en = 0; + ext->drag_right_en = 0; + + uint16_t i; + for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) { + if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y - 1) ext->drag_top_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y + 1) ext->drag_bottom_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x - 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_left_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x + 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_right_en = 1; + } + + return true; +} + + +#endif diff --git a/bdk/libs/lvgl/lv_objx/lv_tileview.h b/bdk/libs/lvgl/lv_objx/lv_tileview.h new file mode 100644 index 0000000..d276fea --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_tileview.h @@ -0,0 +1,163 @@ +/** + * @file lv_tileview.h + * + */ + + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TILEVIEW != 0 + +#include "../lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + + + +/* parametes: pointer to a tileview object, x, y (tile coordinates to load) + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t); + +/*Data of tileview*/ +typedef struct { + lv_page_ext_t page; + /*New data for this type */ + const lv_point_t * valid_pos; + uint16_t anim_time; + lv_tileview_action_t action; + lv_point_t act_id; + uint8_t drag_top_en :1; + uint8_t drag_bottom_en :1; + uint8_t drag_left_en :1; + uint8_t drag_right_en :1; + uint8_t drag_hor :1; + uint8_t drag_ver :1; +} lv_tileview_ext_t; + + +/*Styles*/ +enum { + LV_TILEVIEW_STYLE_BG, +}; +typedef uint8_t lv_tileview_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a tileview objects + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element); + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos); + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param tileview pointer to a Tileview + * @param en true or false to enable/disable end flash + */ +static inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en) +{ + lv_page_set_edge_flash(tileview, en); +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scroll propagation property + * @param tileview pointer to a Tileview + * @return true or false + */ +static inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview) +{ + return lv_page_get_edge_flash(tileview); +} + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TILEVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/bdk/libs/lvgl/lv_objx/lv_win.c b/bdk/libs/lvgl/lv_objx/lv_win.c new file mode 100644 index 0000000..c21c08d --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_win.c @@ -0,0 +1,591 @@ +/* + * 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 . + */ + +/** + * @file lv_win.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_win.h" +#if USE_LV_WIN != 0 + +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param); +static void lv_win_realign(lv_obj_t * win); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("window create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_win = lv_obj_create(par, copy); + lv_mem_assert(new_win); + if(new_win == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_win); + + /*Allocate the object type specific extended data*/ + lv_win_ext_t * ext = lv_obj_allocate_ext_attr(new_win, sizeof(lv_win_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->page = NULL; + ext->header = NULL; + ext->title = NULL; + ext->style_header = &lv_style_plain_color; + ext->style_btn_rel = &lv_style_btn_rel; + ext->style_btn_pr = &lv_style_btn_pr; + ext->btn_size = (LV_DPI) / 2; + + /*Init the new window object*/ + if(copy == NULL) { + lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES); + lv_obj_set_pos(new_win, 0, 0); + lv_obj_set_style(new_win, &lv_style_pretty); + + ext->page = lv_page_create(new_win, NULL); + lv_obj_set_protect(ext->page, LV_PROTECT_PARENT); + lv_page_set_sb_mode(ext->page, LV_SB_MODE_AUTO); + lv_page_set_arrow_scroll(ext->page, true); + + /*Create a holder for the header*/ + ext->header = lv_obj_create(new_win, NULL); + /*Move back the header because it is automatically moved to the scrollable */ + lv_obj_set_protect(ext->header, LV_PROTECT_PARENT); + lv_obj_set_parent(ext->header, new_win); + lv_obj_set_width(ext->header, LV_HOR_RES - 62);//// + ext->btn_size = lv_obj_get_height(ext->header) - 3;//// + + /*Create a title on the header*/ + ext->title = lv_label_create(ext->header, NULL); + lv_label_set_text(ext->title, "My title"); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_win_set_style(new_win, LV_WIN_STYLE_BG, th->win.bg); + lv_win_set_style(new_win, LV_WIN_STYLE_SB, th->win.sb); + lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, th->win.header); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, th->win.content.bg); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, th->win.content.scrl); + lv_win_set_style(new_win, LV_WIN_STYLE_BTN_REL, th->win.btn.rel); + lv_win_set_style(new_win, LV_WIN_STYLE_BTN_PR, th->win.btn.pr); + } else { + lv_win_set_style(new_win, LV_WIN_STYLE_BG, &lv_style_plain); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, &lv_style_plain); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, &lv_style_transp); + lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, &lv_style_plain_color); + } + + lv_obj_set_signal_func(new_win, lv_win_signal); + lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES); + } + /*Copy an existing object*/ + else { + lv_win_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + /*Create the objects*/ + ext->header = lv_obj_create(new_win, copy_ext->header); + ext->title = lv_label_create(ext->header, copy_ext->title); + ext->page = lv_page_create(new_win, copy_ext->page); + ext->btn_size = copy_ext->btn_size; + + /*Copy the control buttons*/ + lv_obj_t * child; + lv_obj_t * cbtn; + child = lv_obj_get_child_back(copy_ext->header, NULL); + child = lv_obj_get_child_back(copy_ext->header, child); /*Sip the title*/ + while(child != NULL) { + cbtn = lv_btn_create(ext->header, child); + lv_img_create(cbtn, lv_obj_get_child(child, NULL)); + child = lv_obj_get_child_back(copy_ext->header, child); + } + + lv_obj_set_signal_func(new_win, lv_win_signal); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_win); + } + + lv_win_realign(new_win); + + LV_LOG_INFO("window created"); + + return new_win; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + lv_obj_t * btn = lv_btn_create(ext->header, NULL); + lv_btn_set_style(btn, LV_BTN_STYLE_REL, ext->style_btn_rel); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, ext->style_btn_pr); + lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size); + lv_btn_set_fit(btn, true, false); + lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, rel_action); + + if (img_src) + { + lv_obj_t * img = lv_img_create(btn, NULL); + lv_obj_set_click(img, false); + lv_img_set_src(img, img_src); + } + else if (label_src) + { + lv_obj_t *label = lv_label_create(btn, NULL); + lv_label_set_recolor(label, true); + lv_label_set_text(label, label_src); + } + + lv_win_realign(win); + + return btn; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn) +{ + lv_obj_t * win = lv_win_get_from_btn(btn); + + lv_obj_del(win); + + return LV_RES_INV; +} + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + lv_label_set_text(ext->title, title); + lv_win_realign(win); +} + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @param size control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + if(ext->btn_size == size) return; + + ext->btn_size = size; + + lv_win_realign(win); +} + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t * win, lv_layout_t layout) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_set_scrl_layout(ext->page, layout); +} + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t * win, lv_sb_mode_t sb_mode) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_set_sb_mode(ext->page, sb_mode); +} + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t * win, lv_win_style_t type, lv_style_t * style) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + switch(type) { + case LV_WIN_STYLE_BG: + lv_obj_set_style(win, style); + lv_win_realign(win); + break; + case LV_WIN_STYLE_CONTENT_BG: + lv_page_set_style(ext->page, LV_PAGE_STYLE_BG, style); + break; + case LV_WIN_STYLE_CONTENT_SCRL: + lv_page_set_style(ext->page, LV_PAGE_STYLE_SCRL, style); + break; + case LV_WIN_STYLE_SB: + lv_page_set_style(ext->page, LV_PAGE_STYLE_SB, style); + break; + case LV_WIN_STYLE_HEADER: + lv_obj_set_style(ext->header, style); + lv_win_realign(win); + break; + case LV_WIN_STYLE_BTN_REL: + ext->style_btn_rel = style; + break; + case LV_WIN_STYLE_BTN_PR: + ext->style_btn_pr = style; + break; + } + + /*Refresh the existing buttons*/ + if(type == LV_WIN_STYLE_BTN_REL || type == LV_WIN_STYLE_BTN_PR) { + lv_obj_t * btn; + btn = lv_obj_get_child_back(ext->header, NULL); + btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/ + while(btn != NULL) { + if(type == LV_WIN_STYLE_BTN_REL) lv_btn_set_style(btn, LV_BTN_STYLE_REL, style); + else lv_btn_set_style(btn, LV_BTN_STYLE_PR, style); + btn = lv_obj_get_child_back(ext->header, btn); + } + } +} + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_obj_t * win_header = ext->header; + lv_obj_set_drag_parent(win_header, en); + lv_obj_set_drag(win, en); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_label_get_text(ext->title); +} + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return ext->page; +} + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return ext->btn_size; +} + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn) +{ + lv_obj_t * header = lv_obj_get_parent(ctrl_btn); + lv_obj_t * win = lv_obj_get_parent(header); + + return win; +} + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_page_get_scrl_layout(ext->page); +} + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_page_get_sb_mode(ext->page); +} + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content_bg area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_obj_t * scrl = lv_page_get_scrl(ext->page); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + + return lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor; +} + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t * win, lv_win_style_t type) +{ + lv_style_t * style = NULL; + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + switch(type) { + case LV_WIN_STYLE_BG: + style = lv_obj_get_style(win); + break; + case LV_WIN_STYLE_CONTENT_BG: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_BG); + break; + case LV_WIN_STYLE_CONTENT_SCRL: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SCRL); + break; + case LV_WIN_STYLE_SB: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SB); + break; + case LV_WIN_STYLE_HEADER: + style = lv_obj_get_style(ext->header); + break; + case LV_WIN_STYLE_BTN_REL: + style = ext->style_btn_rel; + break; + case LV_WIN_STYLE_BTN_PR: + style = ext->style_btn_pr; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_focus(ext->page, obj, anim_time); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the window + * @param win pointer to a window object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(win, sign, param); + if(res != LV_RES_OK) return res; + + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + if(sign == LV_SIGNAL_CHILD_CHG) { /*Move children to the page*/ + lv_obj_t * page = ext->page; + if(page != NULL) { + lv_obj_t * child; + child = lv_obj_get_child(win, NULL); + while(child != NULL) { + if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) { + lv_obj_t * tmp = child; + child = lv_obj_get_child(win, child); /*Get the next child before move this*/ + lv_obj_set_parent(tmp, page); + } else { + child = lv_obj_get_child(win, child); + } + } + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_win_realign(win); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*If the size is changed refresh the window*/ + if(lv_area_get_width(param) != lv_obj_get_width(win) || + lv_area_get_height(param) != lv_obj_get_height(win)) { + lv_win_realign(win); + } + } else if(sign == LV_SIGNAL_CLEANUP) { + ext->header = NULL; /*These objects were children so they are already invalid*/ + ext->page = NULL; + ext->title = NULL; + } else if(sign == LV_SIGNAL_CONTROLL) { + /*Forward all the control signals to the page*/ + ext->page->signal_func(ext->page, sign, param); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_win"; + } + + + return res; +} + +/** + * Realign the building elements of a window + * @param win pointer to window objectker + */ +static void lv_win_realign(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + if(ext->page == NULL || ext->header == NULL || ext->title == NULL) return; + + lv_style_t * header_style = lv_win_get_style(win, LV_WIN_STYLE_HEADER); + lv_obj_set_size(ext->header, lv_obj_get_width(win) - 62, ext->btn_size + 2 * header_style->body.padding.ver); + + bool first_btn = true; + lv_obj_t * btn; + lv_obj_t * btn_prev = NULL; + /*Refresh the size of all control buttons*/ + btn = lv_obj_get_child_back(ext->header, NULL); + btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/ + while(btn != NULL) { + lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size); + if(first_btn) { + lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, - header_style->body.padding.hor, 0); + first_btn = false; + } else { + lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_style->body.padding.inner, 0); + } + btn_prev = btn; + btn = lv_obj_get_child_back(ext->header, btn); + } + + + lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, ext->style_header->body.padding.hor, 0); + + lv_obj_set_pos(ext->header, 31, 0); + + lv_obj_set_size(ext->page, lv_obj_get_width(win), lv_obj_get_height(win) - lv_obj_get_height(ext->header)); + lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); +} + +#endif + diff --git a/bdk/libs/lvgl/lv_objx/lv_win.h b/bdk/libs/lvgl/lv_objx/lv_win.h new file mode 100644 index 0000000..4bb5d00 --- /dev/null +++ b/bdk/libs/lvgl/lv_objx/lv_win.h @@ -0,0 +1,298 @@ +/* + * 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 . + */ + +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_WIN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#if USE_LV_IMG == 0 +#error "lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG 1) " +#endif + + +#if USE_LV_PAGE == 0 +#error "lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" +#include "lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of window*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * page; /*Pointer to a page which holds the content*/ + lv_obj_t * header; /*Pointer to the header container of the window*/ + lv_obj_t * title; /*Pointer to the title label of the window*/ + lv_style_t * style_header; /*Style of the header container*/ + lv_style_t * style_btn_rel; /*Control button releases style*/ + lv_style_t * style_btn_pr; /*Control button pressed style*/ + lv_coord_t btn_size; /*Size of the control buttons (square)*/ +} lv_win_ext_t; + +enum { + LV_WIN_STYLE_BG, + LV_WIN_STYLE_CONTENT_BG, + LV_WIN_STYLE_CONTENT_SCRL, + LV_WIN_STYLE_SB, + LV_WIN_STYLE_HEADER, + LV_WIN_STYLE_BTN_REL, + LV_WIN_STYLE_BTN_PR, +}; +typedef uint8_t lv_win_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action); + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn); + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title); + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size); + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t *win, lv_layout_t layout); + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode); + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style); + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win); + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win); + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win); + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn); + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t *win); + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win); + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win); + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type); + +/** + * Get drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @return whether window is draggable + */ +static inline bool lv_win_get_drag(const lv_obj_t *win) +{ + return lv_obj_get_drag(win); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the window horizontally + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +static inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_hor(ext->page, dist); +} +/** + * Scroll the window vertically + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +static inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_ver(ext->page, dist); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_WIN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_WIN_H*/ diff --git a/bdk/libs/lvgl/lv_themes/lv_theme.c b/bdk/libs/lvgl/lv_themes/lv_theme.c new file mode 100644 index 0000000..59a0489 --- /dev/null +++ b/bdk/libs/lvgl/lv_themes/lv_theme.c @@ -0,0 +1,112 @@ +/** + * @file lv_theme.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_theme.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +#if LV_THEME_LIVE_UPDATE == 0 +static lv_theme_t * current_theme; +#else +/* If live update is used then a big `lv_style_t` array is used to store the real styles of the theme not only pointers. + * On `lv_theme_set_current` the styles of the theme are copied to this array. + * The pointers in `current_theme` are initialized to point to the styles in the array. + * This way the theme styles will always point to the same memory address even after theme is change. + * (The pointers in the theme points to the styles declared by the theme itself) */ + +/* Store the styles in this array. + * Can't determine the size in compile time because sizeof is not evaluated (should be `sizeof(lv_theme_t) / sizeof(lv_style_t*)`). + * Error will be generated in run time if too small.*/ +static lv_style_t th_styles[120]; +static bool inited = false; +static lv_theme_t current_theme; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t * th) +{ +#if LV_THEME_LIVE_UPDATE == 0 + current_theme = th; +#else + uint32_t style_num = sizeof(lv_theme_t) / sizeof(lv_style_t *); /*Number of styles in a theme*/ + + if(!inited) { + /*It's not sure `th_styles` is big enough. Check it now!*/ + if(style_num > sizeof(th_styles) / sizeof(lv_style_t)) { + LV_LOG_ERROR("Themes: th_styles array is too small. Increase it's size!"); + while(1); + } + + /*Initialize the style pointers `current_theme` to point to the `th_styles` style array */ + uint16_t i; + lv_style_t ** cur_th_style_p = (lv_style_t **) ¤t_theme; + for(i = 0; i < style_num; i++) { + uintptr_t adr = (uintptr_t)&th_styles[i]; + memcpy(&cur_th_style_p[i], &adr, sizeof(lv_style_t *)); + } + inited = true; + } + + + /*Copy the styles pointed by the new theme to the `th_styles` style array*/ + uint16_t i; + lv_style_t ** th_style = (lv_style_t **) th; + for(i = 0; i < style_num; i++) { + uintptr_t s = (uintptr_t)th_style[i]; + if(s) memcpy(&th_styles[i], (void *)s, sizeof(lv_style_t)); + } + + /*Let the object know their style might change*/ + lv_obj_report_style_mod(NULL); +#endif +} + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void) +{ +#if LV_THEME_LIVE_UPDATE == 0 + return current_theme; +#else + if(!inited) return NULL; + else return ¤t_theme; +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/bdk/libs/lvgl/lv_themes/lv_theme.h b/bdk/libs/lvgl/lv_themes/lv_theme.h new file mode 100644 index 0000000..f66f9c8 --- /dev/null +++ b/bdk/libs/lvgl/lv_themes/lv_theme.h @@ -0,0 +1,343 @@ +/* + * 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 . + */ + +/** + *@file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_style_t *bg; + lv_style_t *panel; + +#if USE_LV_CONT != 0 + lv_style_t *cont; +#endif + +#if USE_LV_BTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; +#endif + + +#if USE_LV_IMGBTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } imgbtn; +#endif + +#if USE_LV_LABEL != 0 + struct { + lv_style_t *prim; + lv_style_t *sec; + lv_style_t *hint; + } label; +#endif + +#if USE_LV_IMG != 0 + struct { + lv_style_t *light; + lv_style_t *dark; + } img; +#endif + +#if USE_LV_LINE != 0 + struct { + lv_style_t *decor; + } line; +#endif + +#if USE_LV_LED != 0 + lv_style_t *led; +#endif + +#if USE_LV_BAR != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + } bar; +#endif + +#if USE_LV_SLIDER != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob; + } slider; +#endif + +#if USE_LV_LMETER != 0 + lv_style_t *lmeter; +#endif + +#if USE_LV_GAUGE != 0 + lv_style_t *gauge; +#endif + +#if USE_LV_ARC != 0 + lv_style_t *arc; +#endif + +#if USE_LV_PRELOAD != 0 + lv_style_t *preload; +#endif + +#if USE_LV_SW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob_off; + lv_style_t *knob_on; + } sw; +#endif + +#if USE_LV_CHART != 0 + lv_style_t *chart; +#endif + +#if USE_LV_CALENDAR != 0 + struct { + lv_style_t *bg; + lv_style_t *header; + lv_style_t *header_pr; + lv_style_t *day_names; + lv_style_t *highlighted_days; + lv_style_t *inactive_days; + lv_style_t *week_box; + lv_style_t *today_box; + } calendar; +#endif + +#if USE_LV_CB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } box; + } cb; +#endif + +#if USE_LV_BTNM != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } btnm; +#endif + +#if USE_LV_KB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } kb; +#endif + +#if USE_LV_MBOX != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + } btn; + } mbox; +#endif + +#if USE_LV_PAGE != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } page; +#endif + +#if USE_LV_TA != 0 + struct { + lv_style_t *area; + lv_style_t *oneline; + lv_style_t *cursor; + lv_style_t *sb; + } ta; +#endif + +#if USE_LV_SPINBOX != 0 + struct { + lv_style_t *bg; + lv_style_t *cursor; + lv_style_t *sb; + } spinbox; +#endif + +#if USE_LV_LIST + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } list; +#endif + +#if USE_LV_DDLIST != 0 + struct { + lv_style_t *bg; + lv_style_t *bgo; + lv_style_t *pr; + lv_style_t *sel; + lv_style_t *sb; + } ddlist; +#endif + +#if USE_LV_ROLLER != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + } roller; +#endif + +#if USE_LV_TABVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + } btn; + } tabview; +#endif + +#if USE_LV_TILEVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } tileview; +#endif + +#if USE_LV_TABLE != 0 + struct { + lv_style_t *bg; + lv_style_t *cell; + } table; +#endif + +#if USE_LV_WIN != 0 + struct { + lv_style_t *bg; + lv_style_t *sb; + lv_style_t *header; + struct { + lv_style_t *bg; + lv_style_t *scrl; + } content; + struct { + lv_style_t *rel; + lv_style_t *pr; + } btn; + } win; +#endif +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t *th); + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDE + *********************/ +#include "lv_theme_hekate.h" + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c new file mode 100644 index 0000000..d12732c --- /dev/null +++ b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c @@ -0,0 +1,909 @@ +/* + * 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 . + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_theme.h" + +#if USE_LV_THEME_HEKATE + +/********************* + * DEFINES + *********************/ +#define DEF_RADIUS 4 +#define COLOR_SHADOW_LIGHT LV_COLOR_HEX(0xAAAAAA) +#define COLOR_SHADOW_DARK LV_COLOR_HEX(0x1F1F1F) +#define COLOR_HOS_TURQUOISE (lv_color_hsv_to_rgb(_hue, 100, 100)) // 0x00FFC9 +#define COLOR_HOS_TEAL_LIGHTER (lv_color_hsv_to_rgb(_hue, 100, 93)) // 0x00EDBA +#define COLOR_HOS_TEAL_LIGHT (lv_color_hsv_to_rgb(_hue, 100, 72)) // 0x00B78F +#define COLOR_HOS_TEAL (lv_color_hsv_to_rgb(_hue, 100, 64)) // 0x00A273 +#define COLOR_HOS_ORANGE LV_COLOR_HEX(0xFF5500) +#define COLOR_HOS_BG_DARKER LV_COLOR_HEX(0x1B1B1B) +#define COLOR_HOS_BG_DARK LV_COLOR_HEX(0x222222) +#define COLOR_HOS_BG LV_COLOR_HEX(0x2D2D2D) +#define COLOR_HOS_BG_LIGHT LV_COLOR_HEX(0x3D3D3D) +#define COLOR_HOS_LIGHT_BORDER LV_COLOR_HEX(0x4D4D4D) +#define COLOR_HOS_TXT_WHITE LV_COLOR_HEX(0xFBFBFB) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_theme_t theme; +static lv_style_t def; + +/*Static style definitions*/ +static lv_style_t sb; + +/*Saved input parameters*/ +static uint16_t _hue; +static lv_font_t * _font; + +/********************** + * MACROS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void basic_init(void) +{ + static lv_style_t bg, panel; + + lv_style_copy(&def, &lv_style_plain); // Initialize the default style. + def.text.font = _font; + def.body.radius = DEF_RADIUS; + def.text.color = COLOR_HOS_TXT_WHITE; + //def.image.color = COLOR_HOS_TXT_WHITE; //Needed if symbol image. + //def.image.opa = LV_OPA_COVER; + + lv_style_copy(&bg, &def); + bg.body.main_color = COLOR_HOS_BG; + //bg.body.main_color = LV_COLOR_BLACK; + bg.body.grad_color = bg.body.main_color; + bg.body.radius = 0; + bg.body.empty = 1; + + lv_style_copy(&panel, &def); + panel.body.radius = DEF_RADIUS; + panel.body.main_color = COLOR_HOS_BG; + panel.body.grad_color = COLOR_HOS_BG; + panel.body.border.width = 1; + panel.body.border.color = COLOR_HOS_LIGHT_BORDER; + panel.body.border.opa = LV_OPA_COVER; + panel.body.shadow.color = COLOR_SHADOW_LIGHT; + panel.body.shadow.type = LV_SHADOW_BOTTOM; + panel.body.shadow.width = 4; + panel.body.padding.hor = LV_DPI / 8; + panel.body.padding.ver = LV_DPI / 8; + panel.body.padding.inner = LV_DPI / 12; + //panel.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&sb, &def); + sb.body.main_color = LV_COLOR_BLACK; + sb.body.grad_color = LV_COLOR_BLACK; + sb.body.opa = LV_OPA_40; + sb.body.padding.hor = LV_DPI / 25; + + theme.bg = &bg; + theme.panel = &panel; +} + +static void cont_init(void) +{ +#if USE_LV_CONT != 0 + static lv_style_t cont; + lv_style_copy(&cont, theme.panel); + cont.body.shadow.width = 0; + cont.body.border.width = 0; + + theme.cont = &cont; +#endif +} + +static void btn_init(void) +{ +#if USE_LV_BTN != 0 + static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&rel, &def); + rel.body.main_color = COLOR_HOS_BG_LIGHT; + rel.body.grad_color = rel.body.main_color; + rel.body.radius = 6; + rel.body.padding.hor = LV_DPI / 3; + rel.body.padding.ver = LV_DPI / 6; + rel.body.padding.inner = LV_DPI / 10; + rel.body.shadow.color = COLOR_SHADOW_DARK; + rel.body.shadow.type = LV_SHADOW_BOTTOM; + rel.body.shadow.width = 6; + rel.body.border.width = 0; + rel.body.border.color = COLOR_HOS_BG_LIGHT; + rel.body.border.part = LV_BORDER_FULL; + //rel.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&pr, &rel); + pr.body.main_color = LV_COLOR_HEX(0x505050); + pr.body.grad_color = pr.body.main_color; + pr.body.shadow.width = 0; + pr.body.border.color = COLOR_HOS_TEAL_LIGHTER; + pr.text.color = COLOR_HOS_TURQUOISE; + pr.body.border.width = 4; + + lv_style_copy(&tgl_rel, &rel); + tgl_rel.body.border.color = COLOR_HOS_TEAL_LIGHTER; + tgl_rel.body.border.width = 4; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = LV_COLOR_HEX(0x505050); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.text.color = COLOR_HOS_TURQUOISE; + tgl_pr.body.shadow.width = 0; + + lv_style_copy(&ina, &rel); + ina.body.main_color = COLOR_HOS_BG_DARK; + ina.body.grad_color = ina.body.main_color; + //ina.body.shadow.width = 0; + ina.text.color = LV_COLOR_HEX(0x888888); + ina.body.border.width = 4; + + theme.btn.rel = &rel; + theme.btn.pr = ≺ + theme.btn.tgl_rel = &tgl_rel; + theme.btn.tgl_pr = &tgl_pr; + theme.btn.ina = &ina; +#endif +} + + +static void label_init(void) +{ +#if USE_LV_LABEL != 0 + static lv_style_t prim, sec, hint; + + lv_style_copy(&prim, &def); + prim.text.font = _font; + prim.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&sec, &prim); + sec.text.color = COLOR_HOS_ORANGE; + + lv_style_copy(&hint, &prim); + hint.text.color = LV_COLOR_HEX(0xCCCCCC); + + theme.label.prim = &prim; + theme.label.sec = &sec; + theme.label.hint = &hint; +#endif +} + +static void img_init(void) +{ +#if USE_LV_IMG != 0 + static lv_style_t img_light, img_dark; + lv_style_copy(&img_light, &def); + img_light.image.color = LV_COLOR_WHITE; + img_light.image.intense = LV_OPA_80; + + lv_style_copy(&img_dark, &def); + img_dark.image.color = COLOR_HOS_BG_DARKER; + img_dark.image.intense = LV_OPA_80; + + + theme.img.light = &def; + theme.img.dark = &def; +#endif +} + +static void line_init(void) +{ +#if USE_LV_LINE != 0 + static lv_style_t line; + lv_style_copy(&line, &def); + line.line.color = LV_COLOR_HEX(0x656565); + theme.line.decor = &line; +#endif +} + +static void led_init(void) +{ +#if USE_LV_LED != 0 + static lv_style_t led; + lv_style_copy(&led, &def); + led.body.shadow.width = LV_DPI / 10; + led.body.radius = LV_RADIUS_CIRCLE; + led.body.border.width = LV_DPI / 30; + led.body.border.opa = LV_OPA_30; + led.body.main_color = lv_color_hsv_to_rgb(_hue, 100, 100); + led.body.grad_color = lv_color_hsv_to_rgb(_hue, 100, 100); + led.body.border.color = lv_color_hsv_to_rgb(_hue, 60, 60); + led.body.shadow.color = lv_color_hsv_to_rgb(_hue, 100, 100); + + theme.led = &led; +#endif +} + +static void bar_init(void) +{ +#if USE_LV_BAR + static lv_style_t bar_bg, bar_indic; + + lv_style_copy(&bar_bg, &def); + bar_bg.body.main_color = COLOR_HOS_LIGHT_BORDER; + bar_bg.body.grad_color = bar_bg.body.main_color; + bar_bg.body.radius = 3; + bar_bg.body.border.width = 0; + bar_bg.body.padding.hor = LV_DPI / 12; + bar_bg.body.padding.ver = LV_DPI / 12; + + lv_style_copy(&bar_indic, &bar_bg); + bar_indic.body.main_color = COLOR_HOS_TURQUOISE; + bar_indic.body.grad_color = bar_indic.body.main_color; + bar_indic.body.padding.hor = 0; + bar_indic.body.padding.ver = 0; + + theme.bar.bg = &bar_bg; + theme.bar.indic = &bar_indic; +#endif +} + +static void slider_init(void) +{ +#if USE_LV_SLIDER != 0 + static lv_style_t knob; + static lv_style_t slide_bar; + + lv_style_copy(&knob, &def); + knob.body.radius = LV_RADIUS_CIRCLE; + knob.body.border.width = 0; + knob.body.main_color = theme.bar.indic->body.main_color; + knob.body.grad_color = knob.body.main_color; + + lv_style_copy(&slide_bar, theme.bar.indic); + slide_bar.body.main_color = COLOR_HOS_TEAL_LIGHT; + slide_bar.body.grad_color = slide_bar.body.main_color; + + theme.slider.bg = theme.bar.bg; + theme.slider.indic = &slide_bar; + theme.slider.knob = &knob; +#endif +} + +static void sw_init(void) +{ +#if USE_LV_SW != 0 + static lv_style_t sw_bg, sw_indic, sw_knob_off, sw_knob_on; + lv_style_copy(&sw_bg, theme.slider.bg); + sw_bg.body.radius = LV_RADIUS_CIRCLE; + + lv_style_copy(&sw_indic, theme.slider.bg); + sw_indic.body.radius = LV_RADIUS_CIRCLE; + + lv_style_copy(&sw_knob_on, theme.slider.knob); + + lv_style_copy(&sw_knob_off, &sw_knob_on); + sw_knob_off.body.main_color = LV_COLOR_HEX(0xDADADA); + sw_knob_off.body.grad_color = sw_knob_off.body.main_color; + sw_knob_off.body.border.width = 1; + sw_knob_off.body.border.color = LV_COLOR_HEX(0x999999); + sw_knob_off.body.border.opa = LV_OPA_COVER; + + theme.sw.bg = &sw_bg; + theme.sw.indic = &sw_indic; + theme.sw.knob_off = &sw_knob_off; + theme.sw.knob_on = &sw_knob_on; +#endif +} + + +static void lmeter_init(void) +{ +#if USE_LV_LMETER != 0 + static lv_style_t lmeter; + lv_style_copy(&lmeter, &def); + lmeter.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 90); + lmeter.body.grad_color = lmeter.body.main_color; + lmeter.body.padding.hor = LV_DPI / 10; // Scale line length. + lmeter.line.color = LV_COLOR_HEX(0x999999); + lmeter.line.width = 2; + + theme.lmeter = &lmeter; +#endif +} + +static void gauge_init(void) +{ +#if USE_LV_GAUGE != 0 + + static lv_style_t gauge; + lv_style_copy(&gauge, &def); + gauge.body.main_color = lv_color_hsv_to_rgb(_hue, 10, 60); + gauge.body.grad_color = gauge.body.main_color; + gauge.body.padding.hor = LV_DPI / 16; // Scale line length. + gauge.body.padding.inner = LV_DPI / 8; + gauge.body.border.color = LV_COLOR_HEX(0x999999); + gauge.text.color = LV_COLOR_HEX(0xDDDDDD); + gauge.line.width = 3; + gauge.line.color = lv_color_hsv_to_rgb(_hue, 95, 70); + + theme.gauge = &gauge; +#endif +} + +static void arc_init(void) +{ +#if USE_LV_ARC != 0 + + static lv_style_t arc; + lv_style_copy(&arc, &def); + arc.line.width = 10; + arc.line.color = lv_color_hsv_to_rgb(_hue, 90, 90); + + /*For prelaoder*/ + arc.body.border.width = 10; + arc.body.border.color = lv_color_hsv_to_rgb(_hue, 30, 90); + arc.body.padding.hor = 0; + arc.body.padding.ver = 0; + + theme.arc = &arc; +#endif +} + +static void preload_init(void) +{ +#if USE_LV_PRELOAD != 0 + + theme.preload = theme.arc; +#endif +} + +static void chart_init(void) +{ +#if USE_LV_CHART + theme.chart = theme.panel; +#endif +} + +static void calendar_init(void) +{ +#if USE_LV_CALENDAR + static lv_style_t ina_days; + lv_style_copy(&ina_days, &def); + ina_days.text.color = lv_color_hsv_to_rgb(_hue, 0, 70); + + static lv_style_t high_days; + lv_style_copy(&high_days, &def); + high_days.text.color = lv_color_hsv_to_rgb(_hue, 80, 90); + + static lv_style_t week_box; + lv_style_copy(&week_box, &def); + week_box.body.main_color = lv_color_hsv_to_rgb(_hue, 40, 100); + week_box.body.grad_color = lv_color_hsv_to_rgb(_hue, 40, 100); + week_box.body.padding.ver = LV_DPI / 20; + week_box.body.padding.hor = theme.panel->body.padding.hor; + week_box.body.border.color = theme.panel->body.border.color; + week_box.body.border.width = theme.panel->body.border.width; + week_box.body.border.part = LV_BORDER_LEFT | LV_BORDER_RIGHT; + week_box.body.radius = 0; + + static lv_style_t today_box; + lv_style_copy(&today_box, &def); + today_box.body.main_color = LV_COLOR_WHITE; + today_box.body.grad_color = LV_COLOR_WHITE; + today_box.body.padding.ver = LV_DPI / 20; + today_box.body.radius = 0; + + theme.calendar.bg = theme.panel; + theme.calendar.header = &lv_style_transp; + theme.calendar.inactive_days = &ina_days; + theme.calendar.highlighted_days = &high_days; + theme.calendar.week_box = &week_box; + theme.calendar.today_box = &today_box; +#endif +} + +static void cb_init(void) +{ +#if USE_LV_CB != 0 + static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; + lv_style_copy(&rel, theme.panel); + rel.body.shadow.type = LV_SHADOW_FULL; + rel.body.shadow.width = 3; + + lv_style_copy(&pr, &rel); + pr.body.main_color = LV_COLOR_HEX(0xCCCCCC); + pr.body.grad_color = pr.body.main_color; + pr.body.shadow.width = 3; + + lv_style_copy(&tgl_rel, &rel); + tgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 85); + tgl_rel.body.grad_color = tgl_rel.body.main_color; + tgl_rel.body.shadow.width = 0; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 65); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + + lv_style_copy(&ina, theme.btn.ina); + + theme.cb.bg = &lv_style_transp; + theme.cb.box.rel = &rel; + theme.cb.box.pr = ≺ + theme.cb.box.tgl_rel = &tgl_rel; + theme.cb.box.tgl_pr = &tgl_pr; + theme.cb.box.ina = &ina; +#endif +} + + +static void btnm_init(void) +{ +#if USE_LV_BTNM + static lv_style_t bg, rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&bg, theme.panel); + bg.body.padding.hor = 0; + bg.body.padding.ver = 0; + bg.body.padding.inner = 0; + bg.text.color = LV_COLOR_HEX(0x555555); + + lv_style_copy(&rel, theme.panel); + rel.body.border.part = LV_BORDER_FULL | LV_BORDER_INTERNAL; + rel.body.border.width = 1; + rel.body.border.color = LV_COLOR_HEX(0xBBBBBB); + rel.body.empty = 1; + rel.body.shadow.width = 0; + + lv_style_copy(&pr, &rel); + pr.glass = 0; + pr.body.main_color = LV_COLOR_HEX(0xDDDDDD); + pr.body.grad_color = pr.body.main_color; + pr.body.border.width = 0; + pr.body.empty = 0; + + lv_style_copy(&tgl_rel, &pr); + tgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 90, 70); + tgl_rel.body.grad_color = tgl_rel.body.main_color; + tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 95, 65); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + + lv_style_copy(&ina, theme.btn.ina); + + theme.btnm.bg = &bg; + theme.btnm.btn.rel = &rel; + theme.btnm.btn.pr = ≺ + theme.btnm.btn.tgl_rel = &tgl_rel; + theme.btnm.btn.tgl_pr = &tgl_pr; + theme.btnm.btn.ina = &ina; +#endif +} + +static void kb_init(void) +{ +#if USE_LV_KB + + static lv_style_t bg, rel; + + lv_style_copy(&bg, theme.btnm.bg); + bg.text.color = LV_COLOR_HEX(0xCCCCCC); + bg.body.border.width = 0; + bg.body.radius = 0; + bg.body.shadow.color = COLOR_SHADOW_DARK; + bg.body.shadow.type = LV_SHADOW_BOTTOM; + bg.body.shadow.width = 4; + + lv_style_copy(&rel, &lv_style_transp); + rel.text.font = _font; + + theme.kb.bg = &bg; + theme.kb.btn.rel = &rel; + theme.kb.btn.pr = theme.btnm.btn.pr; + theme.kb.btn.tgl_rel = theme.btnm.btn.tgl_rel; + theme.kb.btn.tgl_pr = theme.btnm.btn.tgl_pr; + theme.kb.btn.ina = theme.btnm.btn.ina; +#endif + +} + +static void mbox_init(void) +{ +#if USE_LV_MBOX + static lv_style_t bg; + + lv_style_copy(&bg, theme.panel); + bg.body.main_color = LV_COLOR_HEX(0x464646); + bg.body.grad_color = bg.body.main_color; + bg.body.shadow.color = COLOR_HOS_BG; + bg.body.shadow.type = LV_SHADOW_FULL; + bg.body.shadow.width = 8; + + bg.body.padding.hor = LV_DPI * 3 / 6; + bg.body.padding.ver = LV_DPI / 4; + bg.body.padding.inner = LV_DPI / 3; + + theme.mbox.bg = &bg; + theme.mbox.btn.bg = &lv_style_transp; + theme.mbox.btn.rel = theme.btn.rel; + theme.mbox.btn.pr = theme.btn.pr; +#endif +} + +static void page_init(void) +{ +#if USE_LV_PAGE + theme.page.bg = theme.panel; + theme.page.scrl = &lv_style_transp; + theme.page.sb = &sb; +#endif +} + +static void ta_init(void) +{ +#if USE_LV_TA + static lv_style_t panel, oneline; + + lv_style_copy(&panel, theme.panel); + panel.body.border.width = 0; + panel.body.shadow.color = COLOR_SHADOW_DARK; + panel.body.shadow.type = LV_SHADOW_FULL; + panel.body.shadow.width = 3; + + lv_style_copy(&oneline, &def); + oneline.body.empty = 1; + oneline.body.radius = 0; + oneline.body.border.part = LV_BORDER_BOTTOM; + oneline.body.border.width = 3; + oneline.body.border.color = LV_COLOR_HEX(0x555555); + oneline.body.border.opa = LV_OPA_COVER; + oneline.text.color = LV_COLOR_HEX(0x888888); + + theme.ta.area = &panel; + theme.ta.oneline = &oneline; + theme.ta.cursor = NULL; // Let library to calculate the cursor's style. + theme.ta.sb = &sb; +#endif +} + +static void spinbox_init(void) +{ +#if USE_LV_SPINBOX + theme.spinbox.bg= theme.panel; + theme.spinbox.cursor = theme.ta.cursor; + theme.spinbox.sb = theme.ta.sb; +#endif +} + +static void list_init(void) +{ +#if USE_LV_LIST != 0 + + static lv_style_t list_bg, rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&list_bg, theme.panel); + list_bg.body.padding.hor = 0; + list_bg.body.padding.ver = 0; + list_bg.body.padding.inner = 0; + list_bg.body.shadow.width = 0; + + lv_style_copy(&rel, &lv_style_transp); + rel.body.padding.hor = LV_DPI / 8; + rel.body.padding.ver = LV_DPI / 6; + rel.body.radius = 0; + rel.body.border.color = LV_COLOR_HEX(0x444444); + rel.body.border.width = 1; + rel.body.border.part = LV_BORDER_BOTTOM; + + lv_style_copy(&pr, &rel); + pr.glass = 0; + pr.body.main_color = LV_COLOR_HEX(0x505050); + pr.body.grad_color = pr.body.main_color; + //pr.body.border.width = 1; + pr.body.empty = 0; + //pr.body.radius = 0; + // pr.text.font = _font; + + lv_style_copy(&tgl_rel, &pr); + tgl_rel.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_rel.body.grad_color = tgl_rel.body.main_color; + //tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); + tgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = LV_COLOR_HEX(0x505050); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + + lv_style_copy(&ina, &pr); + ina.body.main_color = COLOR_HOS_BG_DARK; + ina.body.grad_color = ina.body.main_color; + + theme.list.sb = &sb; + theme.list.bg = &list_bg; + theme.list.scrl = &lv_style_transp_tight; + theme.list.btn.rel = &rel; + theme.list.btn.pr = ≺ + theme.list.btn.tgl_rel = &tgl_rel; + theme.list.btn.tgl_pr = &tgl_pr; + theme.list.btn.ina = &ina; +#endif +} + +static void ddlist_init(void) +{ +#if USE_LV_DDLIST != 0 + static lv_style_t bg, sel; + lv_style_copy(&bg, theme.panel); + bg.body.padding.hor = LV_DPI / 6; + //bg.body.padding.ver = LV_DPI / 6; + bg.body.radius = 0; + bg.body.shadow.width = 0; + bg.body.border.width = 0; + bg.text.line_space = LV_DPI / 8; + bg.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&sel, &bg); + sel.body.main_color = COLOR_HOS_BG_LIGHT; + sel.body.grad_color = sel.body.main_color; + + theme.ddlist.bg = &bg; + theme.ddlist.bgo = &bg; + theme.ddlist.pr = &sel; + theme.ddlist.sel = &sel; + theme.ddlist.sb = &sb; +#endif +} + +static void roller_init(void) +{ +#if USE_LV_ROLLER != 0 + static lv_style_t roller_bg, roller_sel; + + lv_style_copy(&roller_bg, &lv_style_transp); + roller_bg.body.padding.hor = LV_DPI / 6; + roller_bg.body.padding.ver = LV_DPI / 6; + roller_bg.text.line_space = LV_DPI / 8; + roller_bg.text.font = _font; + roller_bg.glass = 0; + roller_bg.text.color = LV_COLOR_HEX(0x444444); + + lv_style_copy(&roller_sel, &roller_bg); + roller_sel.text.color = COLOR_HOS_TURQUOISE; + + theme.roller.bg = &roller_bg; + theme.roller.sel = &roller_sel; +#endif +} + +static void tabview_init(void) +{ +#if USE_LV_TABVIEW != 0 + static lv_style_t indic, btn_bg, rel, pr, tgl_rel, tgl_pr; + + lv_style_copy(&indic, &def); + indic.body.main_color = COLOR_HOS_TURQUOISE; + indic.body.grad_color = indic.body.main_color; + indic.body.radius = 0; + indic.body.border.width = 0; + indic.body.padding.inner = LV_DPI / 20; + indic.body.opa = LV_OPA_0; + + lv_style_copy(&btn_bg, &def); + btn_bg.body.main_color = COLOR_HOS_BG; + btn_bg.body.grad_color = btn_bg.body.main_color; + btn_bg.body.radius = 0; + btn_bg.body.empty = 1; + btn_bg.body.border.width = 0; + btn_bg.body.border.color = LV_COLOR_HEX(0xDDDDDD); + btn_bg.body.border.part = LV_BORDER_BOTTOM; + btn_bg.body.border.opa = LV_OPA_COVER; + btn_bg.body.shadow.width = 0; + btn_bg.body.shadow.color = COLOR_SHADOW_LIGHT; + btn_bg.body.shadow.type = LV_SHADOW_BOTTOM; + btn_bg.body.padding.inner = 0; + btn_bg.body.padding.hor = 0; + btn_bg.body.padding.ver = 0; + btn_bg.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&rel, &lv_style_transp); + rel.body.padding.ver = LV_DPI * 4 / 23; + rel.text.font = _font; + + lv_style_copy(&pr, &def); + pr.body.main_color = COLOR_HOS_BG_LIGHT; + pr.body.grad_color = pr.body.main_color; + pr.body.border.width = 0; + pr.body.empty = 0; + pr.body.radius = 0; + pr.body.border.color = LV_COLOR_HEX(0x888888); + pr.body.border.part = LV_BORDER_BOTTOM; + pr.body.border.opa = LV_OPA_COVER; + pr.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&tgl_rel, &lv_style_transp); + tgl_rel.glass = 0; + tgl_rel.text.font = _font; + tgl_rel.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&tgl_pr, &def); + tgl_pr.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + tgl_pr.body.empty = 0; + tgl_pr.body.radius = 0; + tgl_pr.text.color = COLOR_HOS_TURQUOISE; + + theme.tabview.bg = theme.bg; + theme.tabview.indic = &indic; + theme.tabview.btn.bg = &btn_bg; + theme.tabview.btn.rel = &rel; + theme.tabview.btn.pr = ≺ + theme.tabview.btn.tgl_rel = &tgl_rel; + theme.tabview.btn.tgl_pr = &tgl_pr; +#endif +} + +static void tileview_init(void) +{ +#if USE_LV_TILEVIEW != 0 + theme.tileview.bg = &lv_style_transp_tight; + theme.tileview.scrl = &lv_style_transp_tight; + theme.tileview.sb = theme.page.sb; +#endif +} + +static void table_init(void) +{ +#if USE_LV_TABLE != 0 + static lv_style_t cell; + lv_style_copy(&cell, theme.panel); + cell.body.radius = 0; + cell.body.border.width = 1; + cell.body.padding.hor = LV_DPI / 12; + cell.body.padding.ver = LV_DPI / 12; + + theme.table.bg = &lv_style_transp_tight; + theme.table.cell = &cell; +#endif +} + +static void win_init(void) +{ +#if USE_LV_WIN != 0 + static lv_style_t header, rel, pr; + + lv_style_copy(&header, &def); + header.body.main_color = COLOR_HOS_BG; + header.body.grad_color = header.body.main_color; + header.body.radius = 0; + header.body.border.width = 0; + header.body.border.color = LV_COLOR_HEX(0xDDDDDD); + header.body.border.part = LV_BORDER_BOTTOM; + header.body.border.opa = LV_OPA_COVER; + header.body.shadow.width = 0; + header.body.shadow.color = COLOR_SHADOW_LIGHT; + header.body.shadow.type = LV_SHADOW_BOTTOM; + header.body.padding.inner = 0; + header.body.padding.hor = 8; + header.body.padding.ver = 0; + //header.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&rel, theme.btn.rel); + rel.body.radius = 0; + rel.body.opa = LV_OPA_0; + rel.body.border.width = 0; + + lv_style_copy(&pr, theme.btn.pr); + pr.body.radius = 0; + pr.body.border.width = 0; + + theme.win.bg = theme.panel; + theme.win.sb = &sb; + theme.win.header = &header; + theme.win.content.bg = &lv_style_transp; + theme.win.content.scrl = &lv_style_transp; + theme.win.btn.rel = &rel; + theme.win.btn.pr = ≺ +#endif +} + +/********************** + * GLOBAL FUNCTIONS + **********************/ + + + +/** + * Initialize the hekate theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t * font) +{ + if(font == NULL) font = LV_FONT_DEFAULT; + + _hue = hue; + _font = font; + + /*For backward compatibility initialize all theme elements with a default style */ + uint16_t i; + lv_style_t ** style_p = (lv_style_t **) &theme; + for(i = 0; i < sizeof(lv_theme_t) / sizeof(lv_style_t *); i++) { + *style_p = &def; + style_p++; + } + + basic_init(); + cont_init(); + btn_init(); + label_init(); + img_init(); + line_init(); + led_init(); + bar_init(); + slider_init(); + sw_init(); + lmeter_init(); + gauge_init(); + chart_init(); + arc_init(); + preload_init(); + calendar_init(); + cb_init(); + btnm_init(); + kb_init(); + mbox_init(); + page_init(); + ta_init(); + spinbox_init(); + list_init(); + ddlist_init(); + roller_init(); + tabview_init(); + tileview_init(); + table_init(); + win_init(); + + return &theme; +} + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_hekate(void) +{ + return &theme; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif + diff --git a/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h new file mode 100644 index 0000000..cc61d2d --- /dev/null +++ b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h @@ -0,0 +1,71 @@ +/* + * 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 . + */ + +#ifndef LV_THEME_HEKATE_H +#define LV_THEME_HEKATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_THEME_HEKATE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_hekate(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MATERIAL_H*/ diff --git a/bdk/libs/lvgl/lv_themes/lv_themes.mk b/bdk/libs/lvgl/lv_themes/lv_themes.mk new file mode 100644 index 0000000..3345b44 --- /dev/null +++ b/bdk/libs/lvgl/lv_themes/lv_themes.mk @@ -0,0 +1,9 @@ +CSRCS += lv_theme.c +CSRCS += lv_theme_default.c +CSRCS += lv_theme_templ.c +CSRCS += lv_theme_material.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes +VPATH += :$(LVGL_DIR)/lvgl/lv_themes + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes" diff --git a/bdk/libs/lvgl/lv_version.h b/bdk/libs/lvgl/lv_version.h new file mode 100644 index 0000000..ec8fe64 --- /dev/null +++ b/bdk/libs/lvgl/lv_version.h @@ -0,0 +1,66 @@ +/** + * @file lv_version.h + * + */ + +#ifndef LV_VERSION_H +#define LV_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +/*Current version of LittlevGL*/ +#define LVGL_VERSION_MAJOR 5 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_INFO "hekate" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +/* Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + * */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VERSION_H*/ diff --git a/bdk/libs/lvgl/lvgl.h b/bdk/libs/lvgl/lvgl.h new file mode 100644 index 0000000..2d0dd56 --- /dev/null +++ b/bdk/libs/lvgl/lvgl.h @@ -0,0 +1,85 @@ +/** + * @file lvgl.h + * Include all LittleV GL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_version.h" + +#include "lv_misc/lv_log.h" +#include "lv_misc/lv_task.h" + +#include "lv_hal/lv_hal.h" + +#include "lv_core/lv_obj.h" +#include "lv_core/lv_group.h" +#include "lv_core/lv_lang.h" +#include "lv_core/lv_vdb.h" +#include "lv_core/lv_refr.h" + +#include "lv_themes/lv_theme.h" + +#include "lv_objx/lv_btn.h" +#include "lv_objx/lv_imgbtn.h" +#include "lv_objx/lv_img.h" +#include "lv_objx/lv_label.h" +#include "lv_objx/lv_line.h" +#include "lv_objx/lv_page.h" +#include "lv_objx/lv_cont.h" +#include "lv_objx/lv_list.h" +#include "lv_objx/lv_chart.h" +#include "lv_objx/lv_table.h" +#include "lv_objx/lv_cb.h" +#include "lv_objx/lv_bar.h" +#include "lv_objx/lv_slider.h" +#include "lv_objx/lv_led.h" +#include "lv_objx/lv_btnm.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_ddlist.h" +#include "lv_objx/lv_roller.h" +#include "lv_objx/lv_ta.h" +#include "lv_objx/lv_canvas.h" +#include "lv_objx/lv_win.h" +#include "lv_objx/lv_tabview.h" +#include "lv_objx/lv_tileview.h" +#include "lv_objx/lv_mbox.h" +#include "lv_objx/lv_gauge.h" +#include "lv_objx/lv_lmeter.h" +#include "lv_objx/lv_sw.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_arc.h" +#include "lv_objx/lv_preload.h" +#include "lv_objx/lv_calendar.h" +#include "lv_objx/lv_spinbox.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} +#endif + +#endif /*LVGL_H*/ diff --git a/bdk/libs/lvgl/lvgl.mk b/bdk/libs/lvgl/lvgl.mk new file mode 100644 index 0000000..a4f3237 --- /dev/null +++ b/bdk/libs/lvgl/lvgl.mk @@ -0,0 +1,8 @@ +include $(LVGL_DIR)/lvgl/lv_core/lv_core.mk +include $(LVGL_DIR)/lvgl/lv_hal/lv_hal.mk +include $(LVGL_DIR)/lvgl/lv_objx/lv_objx.mk +include $(LVGL_DIR)/lvgl/lv_fonts/lv_fonts.mk +include $(LVGL_DIR)/lvgl/lv_misc/lv_misc.mk +include $(LVGL_DIR)/lvgl/lv_themes/lv_themes.mk +include $(LVGL_DIR)/lvgl/lv_draw/lv_draw.mk + diff --git a/source/mem/emc.h b/bdk/mem/emc.h similarity index 100% rename from source/mem/emc.h rename to bdk/mem/emc.h diff --git a/source/mem/heap.c b/bdk/mem/heap.c similarity index 97% rename from source/mem/heap.c rename to bdk/mem/heap.c index 7c0e202..d249140 100644 --- a/source/mem/heap.c +++ b/bdk/mem/heap.c @@ -1,7 +1,6 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer - * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,8 +17,7 @@ #include #include "heap.h" -#include "../gfx/gfx.h" -#include "../../common/common_heap.h" +#include static void _heap_create(heap_t *heap, u32 start) { @@ -128,6 +126,11 @@ void heap_init(u32 base) _heap_create(&_heap, base); } +void heap_copy(heap_t *heap) +{ + memcpy(&_heap, heap, sizeof(heap_t)); +} + void *malloc(u32 size) { return (void *)_heap_alloc(&_heap, size); diff --git a/common/common_heap.h b/bdk/mem/heap.h similarity index 74% rename from common/common_heap.h rename to bdk/mem/heap.h index f609add..811f13d 100644 --- a/common/common_heap.h +++ b/bdk/mem/heap.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 M4xw + * Copyright (c) 2018-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, @@ -13,11 +13,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ -#pragma once -//TODO: Move it to BDK -#include "../source/utils/types.h" +#ifndef _HEAP_H_ +#define _HEAP_H_ + +#include typedef struct _hnode { @@ -39,3 +40,12 @@ typedef struct u32 total; u32 used; } heap_monitor_t; + +void heap_init(u32 base); +void heap_copy(heap_t *heap); +void *malloc(u32 size); +void *calloc(u32 num, u32 size); +void free(void *buf); +void heap_monitor(heap_monitor_t *mon, bool print_node_stats); + +#endif diff --git a/source/mem/mc.c b/bdk/mem/mc.c similarity index 88% rename from source/mem/mc.c rename to bdk/mem/mc.c index dd508e2..8a0da1a 100644 --- a/source/mem/mc.c +++ b/bdk/mem/mc.c @@ -1,7 +1,24 @@ -#include "../mem/mc.h" -#include "../soc/t210.h" -#include "../soc/clock.h" -#include "../utils/util.h" +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock) { diff --git a/source/mem/heap.h b/bdk/mem/mc.h similarity index 68% rename from source/mem/heap.h rename to bdk/mem/mc.h index e029597..1a9bc83 100644 --- a/source/mem/heap.h +++ b/bdk/mem/mc.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-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, @@ -15,16 +14,17 @@ * along with this program. If not, see . */ -#ifndef _HEAP_H_ -#define _HEAP_H_ +#ifndef _MC_H_ +#define _MC_H_ -#include "../utils/types.h" -#include "../../common/common_heap.h" +#include +#include -void heap_init(u32 base); -void *malloc(u32 size); -void *calloc(u32 num, u32 size); -void free(void *buf); -void heap_monitor(heap_monitor_t *mon, bool print_node_stats); +void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); +void mc_config_carveout(); +void mc_config_carveout_finalize(); +void mc_enable_ahb_redirect(); +void mc_disable_ahb_redirect(); +void mc_enable(); #endif diff --git a/source/mem/mc_t210.h b/bdk/mem/mc_t210.h similarity index 100% rename from source/mem/mc_t210.h rename to bdk/mem/mc_t210.h diff --git a/source/mem/minerva.c b/bdk/mem/minerva.c similarity index 68% rename from source/mem/minerva.c rename to bdk/mem/minerva.c index 2607c4b..259c63a 100644 --- a/source/mem/minerva.c +++ b/bdk/mem/minerva.c @@ -18,15 +18,16 @@ #include #include "minerva.h" -#include "../soc/fuse.h" -#include "../utils/util.h" -#include "../soc/clock.h" -#include "../ianos/ianos.h" -#include "../soc/fuse.h" -#include "../soc/t210.h" +#include +#include +#include +#include +#include +#include extern volatile nyx_storage_t *nyx_str; + void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); u32 minerva_init() @@ -35,6 +36,41 @@ u32 minerva_init() minerva_cfg = NULL; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + +#ifdef NYX + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; + + // Check if Minerva is already initialized. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; // Retrain if needed. + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + minerva_cfg = (void *)ep_addr; + + return 0; + } + else + { + mtc_config_t mtc_tmp; + + mtc_tmp.mtc_table = mtc_cfg->mtc_table; + mtc_tmp.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_tmp.init_done = MTC_NEW_MAGIC; + + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp); + + // Ensure that Minerva is new. + if (mtc_tmp.init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; + + // Copy Minerva context to Nyx storage. + if (minerva_cfg) + memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t)); + } +#else memset(mtc_cfg, 0, sizeof(mtc_config_t)); // Set table to nyx storage. @@ -43,13 +79,14 @@ u32 minerva_init() mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. - u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); // Ensure that Minerva is new. if (mtc_cfg->init_done == MTC_INIT_MAGIC) minerva_cfg = (void *)ep_addr; else mtc_cfg->init_done = 0; +#endif if (!minerva_cfg) return 1; diff --git a/source/mem/minerva.h b/bdk/mem/minerva.h similarity index 98% rename from source/mem/minerva.h rename to bdk/mem/minerva.h index 9be55c9..ed80b95 100644 --- a/source/mem/minerva.h +++ b/bdk/mem/minerva.h @@ -18,7 +18,7 @@ #define _FE_MINERVA_H_ #include "mtc_table.h" -#include "../utils/types.h" +#include #define MTC_INIT_MAGIC 0x3043544D #define MTC_NEW_MAGIC 0x5243544D diff --git a/source/mem/mtc_table.h b/bdk/mem/mtc_table.h similarity index 99% rename from source/mem/mtc_table.h rename to bdk/mem/mtc_table.h index 38a3e2f..e24fa81 100644 --- a/source/mem/mtc_table.h +++ b/bdk/mem/mtc_table.h @@ -20,7 +20,7 @@ #ifndef _MTC_TABLE_H_ #define _MTC_TABLE_H_ -#include "../utils/types.h" +#include typedef struct { diff --git a/source/mem/sdram.c b/bdk/mem/sdram.c similarity index 98% rename from source/mem/sdram.c rename to bdk/mem/sdram.c index 36f54c1..e58a1eb 100644 --- a/source/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -18,23 +18,23 @@ #include -#include "mc.h" -#include "emc.h" -#include "sdram_param_t210.h" -#include "../../common/memory_map.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/fuse.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define CONFIG_SDRAM_KEEP_ALIVE #ifdef CONFIG_SDRAM_COMPRESS_CFG -#include "../libs/compr/lz.h" +#include #include "sdram_config_lz.inl" #else #include "sdram_config.inl" @@ -42,7 +42,7 @@ static u32 _get_sdram_id() { - return ((fuse_read_odm(4) & 0x38) >> 3); + return ((fuse_read_odm(4) & 0xF8) >> 3); } static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) @@ -202,7 +202,7 @@ break_nosleep: EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; - // Patch 4 using BCT spare variables. + // Patch 3 using BCT spare variables. if (params->emc_bct_spare6) *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; @@ -345,7 +345,7 @@ break_nosleep: // Common pad macro (cpm). EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; - // Patch 3 using BCT spare variables. + // Patch 4 using BCT spare variables. if (params->emc_bct_spare4) *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; @@ -723,11 +723,14 @@ sdram_params_t *sdram_get_params() 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: +#ifdef CONFIG_SDRAM_COPPER_SUPPORT + case DRAM_4GB_COPPER_SAMSUNG: + case DRAM_4GB_COPPER_HYNIX: + case DRAM_4GB_COPPER_MICRON: +#endif _sdram_patch_model_params(dramid, (u32 *)buf); break; } diff --git a/source/mem/sdram.h b/bdk/mem/sdram.h similarity index 94% rename from source/mem/sdram.h rename to bdk/mem/sdram.h index 059bc9c..620c078 100644 --- a/source/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -17,8 +17,8 @@ #ifndef _SDRAM_H_ #define _SDRAM_H_ -#include "emc.h" -#include "sdram_param_t210.h" +#include +#include void sdram_init(); sdram_params_t *sdram_get_params(); diff --git a/source/mem/sdram_config.inl b/bdk/mem/sdram_config.inl similarity index 98% rename from source/mem/sdram_config.inl rename to bdk/mem/sdram_config.inl index 58eb62d..42e0555 100644 --- a/source/mem/sdram_config.inl +++ b/bdk/mem/sdram_config.inl @@ -15,15 +15,17 @@ * along with this program. If not, see . */ +#define DRAM_CFG_SIZE 1896 + #define DRAM_ID(x) (1 << (x)) #define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH 0 #define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN 1 #define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2 -#define DRAM_4GB_COPPER_UNK_3 3 // Samsung? +#define DRAM_4GB_COPPER_SAMSUNG 3 #define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH 4 -#define DRAM_4GB_COPPER_UNK_5 5 // Samsung? -#define DRAM_4GB_COPPER_UNK_6 6 // Samsung? +#define DRAM_4GB_COPPER_HYNIX 5 +#define DRAM_4GB_COPPER_MICRON 6 typedef struct _sdram_vendor_patch_t { @@ -658,11 +660,22 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { }; static const sdram_vendor_patch_t sdram_cfg_vendor_patches[] = { - { 0x0000003A, 59, DRAM_ID(6) }, // emc_rfc. Auto refresh. - { 0x0000001D, 60, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. + // Hynix timing config. { 0x0000000D, 67, DRAM_ID(1) | DRAM_ID(5) }, // emc_r2w. { 0x00000001, 91, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_extra. { 0x80000000, 92, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_width. + { 0x00000210, 317, DRAM_ID(1) | DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. + { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. + + // Samsung 6GB density config. + { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB sub-partition density. + { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB sub-partition density. + { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. + +#ifdef CONFIG_SDRAM_COPPER_SUPPORT + // Copper prototype Samsung/Hynix/Micron timing configs. + { 0x0000003A, 59, DRAM_ID(6) }, // emc_rfc. Auto refresh. + { 0x0000001D, 60, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. { 0x00000012, 108, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. { 0x0000003B, 112, DRAM_ID(6) }, // emc_txsr. { 0x0000003B, 113, DRAM_ID(6) }, // emc_txsr_dll. @@ -687,11 +700,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches[] = { { 0x00000015, 237, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4. { 0x00000012, 295, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2. { 0x00000012, 296, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3. - { 0x00000210, 317, DRAM_ID(1) | DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. - { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB sub-partition density. - { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB sub-partition density. - { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. - { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. { 0x00000007, 370, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh. - { 0x72A30504, 373, DRAM_ID(6) } // mc_emem_arb_misc0. + { 0x72A30504, 373, DRAM_ID(6) }, // mc_emem_arb_misc0. +#endif }; diff --git a/source/mem/sdram_config_lz.inl b/bdk/mem/sdram_config_lz.inl similarity index 100% rename from source/mem/sdram_config_lz.inl rename to bdk/mem/sdram_config_lz.inl diff --git a/source/mem/sdram_lp0.c b/bdk/mem/sdram_lp0.c similarity index 99% rename from source/mem/sdram_lp0.c rename to bdk/mem/sdram_lp0.c index 869e85a..2a83c27 100644 --- a/source/mem/sdram_lp0.c +++ b/bdk/mem/sdram_lp0.c @@ -14,9 +14,9 @@ * more details. */ -#include "../soc/t210.h" -#include "../soc/pmc_lp0_t210.h" -#include "sdram_lp0_param_t210.h" +#include +#include +#include /* * This function reads SDRAM parameters from the common BCT format and diff --git a/source/mem/sdram_lp0_param_t210.h b/bdk/mem/sdram_lp0_param_t210.h similarity index 99% rename from source/mem/sdram_lp0_param_t210.h rename to bdk/mem/sdram_lp0_param_t210.h index 9028990..1422ed3 100644 --- a/source/mem/sdram_lp0_param_t210.h +++ b/bdk/mem/sdram_lp0_param_t210.h @@ -23,7 +23,7 @@ #ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ #define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ -#include "../utils/types.h" +#include enum { diff --git a/source/mem/sdram_param_t210.h b/bdk/mem/sdram_param_t210.h similarity index 99% rename from source/mem/sdram_param_t210.h rename to bdk/mem/sdram_param_t210.h index 4980918..4c6c60a 100644 --- a/source/mem/sdram_param_t210.h +++ b/bdk/mem/sdram_param_t210.h @@ -113,7 +113,6 @@ typedef struct _sdram_params /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ u32 emc_auto_cal_config3; - u32 emc_auto_cal_config4; u32 emc_auto_cal_config5; u32 emc_auto_cal_config6; diff --git a/source/soc/smmu.c b/bdk/mem/smmu.c similarity index 94% rename from source/soc/smmu.c rename to bdk/mem/smmu.c index fb096d4..6ee99b9 100644 --- a/source/soc/smmu.c +++ b/bdk/mem/smmu.c @@ -17,12 +17,12 @@ #include -#include "smmu.h" -#include "../soc/cluster.h" -#include "../soc/t210.h" -#include "../mem/mc_t210.h" -#include "../utils/util.h" -#include "../utils/aarch64_util.h" +#include +#include +#include +#include +#include +#include bool smmu_used = false; u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR; @@ -92,7 +92,7 @@ void smmu_enable() if (smmu_used) return; - cluster_boot_cpu0((u32)smmu_payload); + ccplex_boot_cpu0((u32)smmu_payload); smmu_used = true; msleep(150); diff --git a/source/soc/smmu.h b/bdk/mem/smmu.h similarity index 99% rename from source/soc/smmu.h rename to bdk/mem/smmu.h index 827d58b..7846253 100644 --- a/source/soc/smmu.h +++ b/bdk/mem/smmu.h @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -#include "../utils/types.h" +#include #define SMMU_HEAP_ADDR 0xA0000000 diff --git a/common/memory_map.h b/bdk/memory_map.h similarity index 96% rename from common/memory_map.h rename to bdk/memory_map.h index a1a41cb..6e92668 100644 --- a/common/memory_map.h +++ b/bdk/memory_map.h @@ -42,6 +42,7 @@ // Virtual disk / Chainloader buffers. #define RAM_DISK_ADDR 0xA4000000 +#define NX_BIS_CACHE_ADDR RAM_DISK_ADDR #define RAM_DISK_SZ 0x41000000 // 1040MB. //#define DRAM_LIB_ADDR 0xE0000000 @@ -83,8 +84,8 @@ #define DRAM_START2 0xFEB40000 // NX BIS driver sector cache. -#define NX_BIS_CACHE_ADDR 0xFEE00000 -#define NX_BIS_CACHE_SZ 0x8800 +// #define NX_BIS_CACHE_ADDR 0xFEE00000 +// #define NX_BIS_CACHE_SZ 0x100000 // USB buffers. #define USBD_ADDR 0xFEF00000 diff --git a/common/common_module.h b/bdk/module.h similarity index 86% rename from common/common_module.h rename to bdk/module.h index 1d3fb89..6ec303f 100644 --- a/common/common_module.h +++ b/bdk/module.h @@ -1,6 +1,6 @@ /* * Common Module Header - * Copyright (C) 2018 M4xw + * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -15,11 +15,11 @@ * along with this program. If not, see . */ -#pragma once +#ifndef _MODULE_H_ +#define _MODULE_H_ + #include -//TODO: Move it to BDK -#include "common_gfx.h" -#include "common_heap.h" +#include // Module Callback typedef void (*cbMainModule_t)(const char *s); @@ -28,8 +28,8 @@ typedef void (*memset_t)(void *, int, size_t); typedef struct _bdkParams_t { - gfx_con_t *gfxCon; - gfx_ctxt_t *gfxCtx; + void *gfxCon; + void *gfxCtx; heap_t *sharedHeap; memcpy_t memcpy; memset_t memset; @@ -37,3 +37,5 @@ typedef struct _bdkParams_t // Module Entrypoint typedef void (*moduleEntrypoint_t)(void *, bdkParams_t); + +#endif diff --git a/bdk/power/bq24193.c b/bdk/power/bq24193.c new file mode 100644 index 0000000..2b2e744 --- /dev/null +++ b/bdk/power/bq24193.c @@ -0,0 +1,178 @@ +/* + * 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 . + */ + +#include "bq24193.h" +#include +#include + +static u8 bq24193_get_reg(u8 reg) +{ + return i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg); +} + +int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) +{ + u8 data; + + switch (prop) { + case BQ24193_InputVoltageLimit: // Input voltage limit (mV). + data = bq24193_get_reg(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 = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_PORConfig); + *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; + *value *= 100; + *value += 3000; + break; + case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). + data = bq24193_get_reg(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 = bq24193_get_reg(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 = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_ChrgVolt); + data &= BQ24193_IRTHERMAL_THERM_MASK; + if (data) + *value = 300; + else + *value = 100; + break; + case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). + data = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_Status); + *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; + break; + case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. + data = bq24193_get_reg(BQ24193_FaultReg); + *value = data & BQ24193_FAULT_THERM_MASK; + break; + case BQ24193_DevID: // Dev ID. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = data & BQ24193_VENDORPART_DEV_MASK; + break; + case BQ24193_ProductNumber: // Product number. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; + break; + default: + return -1; + } + return 0; +} + +void bq24193_enable_charger() +{ + u8 reg = bq24193_get_reg(BQ24193_PORConfig); + + reg &= ~BQ24193_PORCONFIG_CHGCONFIG_MASK; + reg |= BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN; + + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg); +} + +void bq24193_fake_battery_removal() +{ + // Disable watchdog to keep BATFET disabled. + u8 value = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_Misc); + value |= BQ24193_MISC_BATFET_DI_MASK; + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value); +} diff --git a/bdk/power/bq24193.h b/bdk/power/bq24193.h new file mode 100644 index 0000000..1b6e717 --- /dev/null +++ b/bdk/power/bq24193.h @@ -0,0 +1,121 @@ +/* + * 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 . + */ + +#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_CHGCONFIG_CHARGER_EN (1<<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_enable_charger(); +void bq24193_fake_battery_removal(); + +#endif /* __BQ24193_H_ */ diff --git a/source/power/max17050.c b/bdk/power/max17050.c similarity index 81% rename from source/power/max17050.c rename to bdk/power/max17050.c index 635a437..2491466 100644 --- a/source/power/max17050.c +++ b/bdk/power/max17050.c @@ -23,8 +23,8 @@ */ #include "max17050.h" -#include "../soc/i2c.h" -#include "../utils/util.h" +#include +#include /* Status register bits */ #define STATUS_POR_BIT (1 << 1) @@ -43,8 +43,20 @@ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ -#pragma GCC push_options -#pragma GCC optimize ("Os") +static u32 battery_voltage = 0; +u32 max17050_get_cached_batt_volt() +{ + return battery_voltage; +} + +static u16 max17050_get_reg(u8 reg) +{ + u16 data = 0; + + i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); + + return data; +} int max17050_get_property(enum MAX17050_reg reg, int *value) { @@ -53,66 +65,64 @@ int max17050_get_property(enum MAX17050_reg reg, int *value) switch (reg) { case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap). - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Age); + data = max17050_get_reg(MAX17050_Age); *value = data >> 8; /* Show MSB. 1% increments */ break; case MAX17050_Cycles: // Cycle count. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Cycles); + *value = max17050_get_reg(MAX17050_Cycles); break; case MAX17050_MinVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); + data = max17050_get_reg(MAX17050_MinMaxVolt); *value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */ break; case MAX17050_MaxVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); + data = max17050_get_reg(MAX17050_MinMaxVolt); *value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */ break; case MAX17050_V_empty: // Voltage min design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_V_empty); + data = max17050_get_reg(MAX17050_V_empty); *value = (data >> 7) * 10; /* Units of LSB = 10mV */ break; case MAX17050_VCELL: // Voltage now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL); + data = max17050_get_reg(MAX17050_VCELL); *value = data * 625 / 8 / 1000; + battery_voltage = *value; break; case MAX17050_AvgVCELL: // Voltage avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL); + data = max17050_get_reg(MAX17050_AvgVCELL); *value = data * 625 / 8 / 1000; break; case MAX17050_OCVInternal: // Voltage ocv. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_OCVInternal); + data = max17050_get_reg(MAX17050_OCVInternal); *value = data * 625 / 8 / 1000; break; case MAX17050_RepSOC: // Capacity %. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC); + *value = max17050_get_reg(MAX17050_RepSOC); break; case MAX17050_DesignCap: // Charge full design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_DesignCap); + *value = data * 5 / 10; break; case MAX17050_FullCAP: // Charge full. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullCAP); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_FullCAP); + *value = data * 5 / 10; break; case MAX17050_RepCap: // Charge now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepCap); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_RepCap); + *value = data * 5 / 10; break; case MAX17050_TEMP: // Temp. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_TEMP); + data = max17050_get_reg(MAX17050_TEMP); *value = (s16)data; *value = *value * 10 / 256; break; case MAX17050_Current: // Current now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Current); + data = max17050_get_reg(MAX17050_Current); *value = (s16)data; *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; break; case MAX17050_AvgCurrent: // Current avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgCurrent); + data = max17050_get_reg(MAX17050_AvgCurrent); *value = (s16)data; *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; break; @@ -131,7 +141,7 @@ static int _max17050_write_verify_reg(u8 reg, u16 value) do { ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); - i2c_recv_buf_small((u8 *)&read_value, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); + read_value = max17050_get_reg(reg); if (read_value != value) { ret = -1; @@ -267,5 +277,3 @@ int max17050_fix_configuration() return 0; } - -#pragma GCC pop_options \ No newline at end of file diff --git a/source/power/max17050.h b/bdk/power/max17050.h similarity index 99% rename from source/power/max17050.h rename to bdk/power/max17050.h index eb55e65..254aca3 100644 --- a/source/power/max17050.h +++ b/bdk/power/max17050.h @@ -24,7 +24,7 @@ #ifndef __MAX17050_H_ #define __MAX17050_H_ -#include "../utils/types.h" +#include #define MAX17050_STATUS_BattAbsent (1 << 3) #define MAX17050_DEFAULT_SNS_RESISTOR 10000 diff --git a/source/power/max77620.h b/bdk/power/max77620.h similarity index 100% rename from source/power/max77620.h rename to bdk/power/max77620.h diff --git a/source/power/max7762x.c b/bdk/power/max7762x.c similarity index 98% rename from source/power/max7762x.c rename to bdk/power/max7762x.c index ce07cbe..425ce1f 100644 --- a/source/power/max7762x.c +++ b/bdk/power/max7762x.c @@ -15,10 +15,10 @@ * along with this program. If not, see . */ -#include "max7762x.h" -#include "max77620.h" -#include "../soc/i2c.h" -#include "../utils/util.h" +#include +#include +#include +#include #define REGULATOR_SD 0 #define REGULATOR_LDO 1 diff --git a/source/power/max7762x.h b/bdk/power/max7762x.h similarity index 98% rename from source/power/max7762x.h rename to bdk/power/max7762x.h index 8a11a9f..f60c3b2 100644 --- a/source/power/max7762x.h +++ b/bdk/power/max7762x.h @@ -18,7 +18,7 @@ #ifndef _MAX7762X_H_ #define _MAX7762X_H_ -#include "../utils/types.h" +#include /* * Switch Power domains (max77620): @@ -64,7 +64,7 @@ #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_VOUT_REG 0 -#define MAX77621_VOUT_DVC_REG 1 +#define MAX77621_VOUT_DVS_REG 1 #define MAX77621_CONTROL1_REG 2 #define MAX77621_CONTROL2_REG 3 diff --git a/bdk/power/regulator_5v.c b/bdk/power/regulator_5v.c new file mode 100644 index 0000000..c61db64 --- /dev/null +++ b/bdk/power/regulator_5v.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +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); +} diff --git a/common/common_gfx.h b/bdk/power/regulator_5v.h similarity index 57% rename from common/common_gfx.h rename to bdk/power/regulator_5v.h index d2e579f..e916fbd 100644 --- a/common/common_gfx.h +++ b/bdk/power/regulator_5v.h @@ -1,9 +1,6 @@ /* - * Common Gfx Header - * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer - * Copyright (C) 2018 M4xw - * + * 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. @@ -15,30 +12,23 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ -#pragma once -//TODO: Move it to BDK -#include "../source/utils/types.h" +#ifndef _REGULATOR_5V_H_ +#define _REGULATOR_5V_H_ -typedef struct _gfx_ctxt_t +#include + +enum { - u32 *fb; - u32 width; - u32 height; - u32 stride; -} gfx_ctxt_t; + REGULATOR_5V_FAN = (1 << 0), + REGULATOR_5V_JC_R = (1 << 1), + REGULATOR_5V_JC_L = (1 << 2), + REGULATOR_5V_ALL = 0xFF +}; -typedef struct _gfx_con_t -{ - gfx_ctxt_t *gfx_ctxt; - u32 fntsz; - u32 x; - u32 y; - u32 savedx; - u32 savedy; - u32 fgcol; - int fillbg; - u32 bgcol; - bool mute; -} gfx_con_t; +void regulator_enable_5v(u8 dev); +void regulator_disable_5v(u8 dev); +bool regulator_get_5v_dev_enabled(u8 dev); + +#endif \ No newline at end of file diff --git a/source/rtc/max77620-rtc.c b/bdk/rtc/max77620-rtc.c similarity index 81% rename from source/rtc/max77620-rtc.c rename to bdk/rtc/max77620-rtc.c index d2a780a..164df75 100644 --- a/source/rtc/max77620-rtc.c +++ b/bdk/rtc/max77620-rtc.c @@ -2,7 +2,7 @@ * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,9 +17,9 @@ * along with this program. If not, see . */ -#include "max77620-rtc.h" -#include "../soc/i2c.h" -#include "../utils/util.h" +#include +#include +#include void max77620_rtc_get_time(rtc_time_t *time) { @@ -35,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time) // Get time. time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; + 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) && time->hour & MAX77620_RTC_HOUR_PM_MASK) + if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK)) time->hour = (time->hour & 0xF) + 12; // Get day of week. 1: Monday to 7: Sunday. @@ -119,7 +119,7 @@ void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) time->weekday = 0; //! TODO. } -u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time) { u32 year, month, epoch; @@ -128,39 +128,17 @@ u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) //Month of year month = time->month; - if (!hos_encoding) + // Month/Year offset. + if(month < 3) { - // 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; + month += 12; + year--; } 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 += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. + epoch -= 719561; // Epoch time is 1/1/1970. epoch *= 86400; // Days to seconds. epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds. diff --git a/source/rtc/max77620-rtc.h b/bdk/rtc/max77620-rtc.h similarity index 95% rename from source/rtc/max77620-rtc.h rename to bdk/rtc/max77620-rtc.h index 99199d2..d9e216a 100644 --- a/source/rtc/max77620-rtc.h +++ b/bdk/rtc/max77620-rtc.h @@ -19,7 +19,7 @@ #ifndef _MFD_MAX77620_RTC_H_ #define _MFD_MAX77620_RTC_H_ -#include "../utils/types.h" +#include #define MAX77620_RTC_I2C_ADDR 0x68 @@ -72,6 +72,6 @@ typedef struct _rtc_time_t { void max77620_rtc_get_time(rtc_time_t *time); 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); +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time); #endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/source/sec/se.c b/bdk/sec/se.c similarity index 90% rename from source/sec/se.c rename to bdk/sec/se.c index c6dbd8e..8cd5c2c 100644 --- a/source/sec/se.c +++ b/bdk/sec/se.c @@ -19,13 +19,13 @@ #include -#include "../../common/memory_map.h" -#include "../sec/se.h" -#include "../mem/heap.h" -#include "../soc/bpmp.h" -#include "../soc/t210.h" -#include "../sec/se_t210.h" -#include "../utils/util.h" +#include "se.h" +#include "se_t210.h" +#include +#include +#include +#include +#include typedef struct _se_ll_t { @@ -55,18 +55,18 @@ static void _gf256_mul_x(void *block) static void _gf256_mul_x_le(void *block) { - u32 *pdata = (u32 *)block; - u32 carry = 0; + u32 *pdata = (u32 *)block; + u32 carry = 0; - for (u32 i = 0; i < 4; i++) + for (u32 i = 0; i < 4; i++) { - u32 b = pdata[i]; - pdata[i] = (b << 1) | carry; - carry = b >> 31; - } + u32 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 31; + } - if (carry) - pdata[0x0] ^= 0x87; + if (carry) + pdata[0x0] ^= 0x87; } static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) @@ -342,16 +342,16 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s } // random calls were derived from Atmosphère's -int se_initialize_rng(u32 ks) +int se_initialize_rng() { u8 *output_buf = (u8 *)malloc(0x10); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001; - SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); + SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | + SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0); @@ -360,11 +360,10 @@ int se_initialize_rng(u32 ks) return res; } -int se_generate_random(u32 ks, void *dst, u32 size) +int se_generate_random(void *dst, u32 size) { SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); u32 num_blocks = size >> 4; @@ -417,11 +416,10 @@ int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, return _se_execute(OP_START, dst, dst_size, src, src_size); } -int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize) +int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size) { - int res = 0; - u8 *tweak = (u8 *)malloc(0x10); - u8 *temptweak = (u8 *)malloc(0x10); + u8 tweak[0x10]; + u8 orig_tweak[0x10]; u32 *pdst = (u32 *)dst; u32 *psrc = (u32 *)src; u32 *ptweak = (u32 *)tweak; @@ -432,49 +430,46 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo tweak[i] = sec & 0xFF; sec >>= 8; } - if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) - goto out; + if (!se_aes_crypt_block_ecb(tweak_ks, 1, tweak, tweak)) + return 0; - memcpy(temptweak, tweak, 0x10); + memcpy(orig_tweak, tweak, 0x10); - //We are assuming a 0x10-aligned sector size in this implementation. - for (u32 i = 0; i < secsize / 0x10; i++) + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < sec_size / 0x10; i++) { for (u32 j = 0; j < 4; j++) pdst[j] = psrc[j] ^ ptweak[j]; + _gf256_mul_x_le(tweak); psrc += 4; pdst += 4; } - se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); + if (!se_aes_crypt_ecb(crypt_ks, enc, dst, sec_size, dst, sec_size)) + return 0; pdst = (u32 *)dst; - - memcpy(tweak, temptweak, 0x10); - for (u32 i = 0; i < secsize / 0x10; i++) + ptweak = (u32 *)orig_tweak; + for (u32 i = 0; i < sec_size / 0x10; i++) { for (u32 j = 0; j < 4; j++) pdst[j] = pdst[j] ^ ptweak[j]; - _gf256_mul_x_le(tweak); + + _gf256_mul_x_le(orig_tweak); pdst += 4; } - res = 1; - -out:; - free(temptweak); - free(tweak); - return res; + return 1; } -int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs) +int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs) { u8 *pdst = (u8 *)dst; u8 *psrc = (u8 *)src; for (u32 i = 0; i < num_secs; i++) - if (!se_aes_xts_crypt_sec(ks1, ks2, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize)) + if (!se_aes_xts_crypt_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + sec_size * i, psrc + sec_size * i, sec_size)) return 0; return 1; diff --git a/source/sec/se.h b/bdk/sec/se.h similarity index 85% rename from source/sec/se.h rename to bdk/sec/se.h index 5172403..ed4f40f 100644 --- a/source/sec/se.h +++ b/bdk/sec/se.h @@ -17,7 +17,7 @@ #ifndef _SE_H_ #define _SE_H_ -#include "../utils/types.h" +#include void se_rsa_acc_ctrl(u32 rs, u32 flags); void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size); @@ -29,16 +29,16 @@ void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_iv_set(u32 ks, const void *iv, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size); void se_aes_key_clear(u32 ks); -int se_initialize_rng(u32 ks); -int se_generate_random(u32 ks, void *dst, u32 size); +int se_initialize_rng(); +int se_generate_random(void *dst, u32 size); int se_generate_random_key(u32 ks_dst, u32 ks_src); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); -int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize); -int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); +int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size); +int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); diff --git a/source/sec/se_t210.h b/bdk/sec/se_t210.h similarity index 99% rename from source/sec/se_t210.h rename to bdk/sec/se_t210.h index 01828c7..83557f7 100644 --- a/source/sec/se_t210.h +++ b/bdk/sec/se_t210.h @@ -21,7 +21,7 @@ #ifndef _CRYPTO_TEGRA_SE_H #define _CRYPTO_TEGRA_SE_H -#include "../utils/types.h" +#include #define TEGRA_SE_CRA_PRIORITY 300 #define TEGRA_SE_COMPOSITE_PRIORITY 400 diff --git a/source/sec/tsec.c b/bdk/sec/tsec.c similarity index 93% rename from source/sec/tsec.c rename to bdk/sec/tsec.c index 0a8169e..3361144 100644 --- a/source/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -18,20 +18,22 @@ #include -#include "../hos/hos.h" -#include "../sec/tsec.h" -#include "../sec/tsec_t210.h" -#include "../sec/se_t210.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/kfuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../utils/util.h" +#include "tsec.h" +#include "tsec_t210.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include -// #include "../gfx/gfx.h" +// #include + +#define PKG11_MAGIC 0x31314B50 +#define KB_TSEC_FW_EMU_COMPAT 6 // KB ID for HOS 6.2.0. static int _tsec_dma_wait_idle() { @@ -104,7 +106,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } //Load firmware or emulate memio environment for newer TSEC fw. - if (kb == KB_FIRMWARE_VERSION_620) + if (kb == KB_TSEC_FW_EMU_COMPAT) TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; else { @@ -123,7 +125,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } } - if (kb == KB_FIRMWARE_VERSION_620) + if (kb == KB_TSEC_FW_EMU_COMPAT) { // Init SMMU translation for TSEC. pdir = smmu_init_for_tsec(); @@ -185,14 +187,14 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - if (kb == KB_FIRMWARE_VERSION_620) + if (kb == KB_TSEC_FW_EMU_COMPAT) { u32 start = get_tmr_us(); u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; u32 key[16] = {0}; u32 kidx = 0; - while (*pkg11_magic_off != HOS_PKG11_MAGIC) + while (*pkg11_magic_off != PKG11_MAGIC) { smmu_flush_all(); diff --git a/source/sec/tsec.h b/bdk/sec/tsec.h similarity index 97% rename from source/sec/tsec.h rename to bdk/sec/tsec.h index 5d15fb5..29b9317 100644 --- a/source/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -18,7 +18,7 @@ #ifndef _TSEC_H_ #define _TSEC_H_ -#include "../utils/types.h" +#include #define TSEC_KEY_DATA_ADDR 0x300 diff --git a/source/sec/tsec_t210.h b/bdk/sec/tsec_t210.h similarity index 100% rename from source/sec/tsec_t210.h rename to bdk/sec/tsec_t210.h diff --git a/source/soc/bpmp.c b/bdk/soc/bpmp.c similarity index 98% rename from source/soc/bpmp.c rename to bdk/soc/bpmp.c index eea0de5..1a8a205 100644 --- a/source/soc/bpmp.c +++ b/bdk/soc/bpmp.c @@ -16,11 +16,11 @@ * along with this program. If not, see . */ -#include "bpmp.h" -#include "clock.h" -#include "t210.h" -#include "../../common/memory_map.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include #define BPMP_MMU_CACHE_LINE_SIZE 0x20 diff --git a/source/soc/bpmp.h b/bdk/soc/bpmp.h similarity index 98% rename from source/soc/bpmp.h rename to bdk/soc/bpmp.h index aad901a..81f000b 100644 --- a/source/soc/bpmp.h +++ b/bdk/soc/bpmp.h @@ -19,7 +19,7 @@ #ifndef _BPMP_H_ #define _BPMP_H_ -#include "../utils/types.h" +#include typedef enum { diff --git a/source/soc/cluster.c b/bdk/soc/ccplex.c similarity index 88% rename from source/soc/cluster.c rename to bdk/soc/ccplex.c index 79538ed..24a4787 100644 --- a/source/soc/cluster.c +++ b/bdk/soc/ccplex.c @@ -14,16 +14,16 @@ * along with this program. If not, see . */ -#include "../soc/cluster.h" -#include "../soc/i2c.h" -#include "../soc/clock.h" -#include "../utils/util.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" +#include +#include +#include +#include +#include +#include +#include +#include -void _cluster_enable_power() +void _ccplex_enable_power() { u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing. @@ -37,10 +37,10 @@ void _cluster_enable_power() i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); } -int _cluster_pmc_enable_partition(u32 part, int enable) +int _ccplex_pmc_enable_partition(u32 part, int enable) { u32 part_mask = 1 << part; u32 desired_state = enable << part; @@ -73,12 +73,12 @@ int _cluster_pmc_enable_partition(u32 part, int enable) return 1; } -void cluster_boot_cpu0(u32 entry) +void ccplex_boot_cpu0(u32 entry) { // Set ACTIVE_CLUSER to FAST. FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; - _cluster_enable_power(); + _ccplex_enable_power(); if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. { @@ -107,11 +107,11 @@ void cluster_boot_cpu0(u32 entry) CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; // Enable CPU rail. - _cluster_pmc_enable_partition(0, 1); + _ccplex_pmc_enable_partition(0, 1); // Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(15, 1); + _ccplex_pmc_enable_partition(15, 1); // Enable CE0. - _cluster_pmc_enable_partition(14, 1); + _ccplex_pmc_enable_partition(14, 1); // Request and wait for RAM repair. FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; diff --git a/source/soc/cluster.h b/bdk/soc/ccplex.h similarity index 86% rename from source/soc/cluster.h rename to bdk/soc/ccplex.h index 428c046..fb5be92 100644 --- a/source/soc/cluster.h +++ b/bdk/soc/ccplex.h @@ -14,11 +14,11 @@ * along with this program. If not, see . */ -#ifndef _CLUSTER_H_ -#define _CLUSTER_H_ +#ifndef _CCPLEX_H_ +#define _CCPLEX_H_ -#include "../utils/types.h" +#include -void cluster_boot_cpu0(u32 entry); +void ccplex_boot_cpu0(u32 entry); #endif diff --git a/source/soc/clock.c b/bdk/soc/clock.c similarity index 89% rename from source/soc/clock.c rename to bdk/soc/clock.c index 60a069b..41e69a2 100644 --- a/source/soc/clock.c +++ b/bdk/soc/clock.c @@ -15,10 +15,10 @@ * along with this program. If not, see . */ -#include "../soc/clock.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "../storage/sdmmc.h" +#include +#include +#include +#include /* * CLOCK Peripherals: @@ -276,7 +276,7 @@ void clock_enable_pllc(u32 divn) return; // Take PLLC out of reset and set basic misc parameters. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = + 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. @@ -312,6 +312,56 @@ void clock_disable_pllc() usleep(10); } +#define PLLC4_ENABLED (1 << 31) +#define PLLC4_IN_USE (~PLLC4_ENABLED) + +u32 pllc4_enabled = 0; + +static void _clock_enable_pllc4(u32 mask) +{ + pllc4_enabled |= mask; + + if (pllc4_enabled & PLLC4_ENABLED) + return; + + // Enable Phase and Frequency lock detection. + //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; + usleep(10); + + // Set PLLC4 dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (104 << 8) | 4; // DIVM: 4, DIVP: 1. + + // Enable PLLC4 and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) + ; + + msleep(1); // Wait a bit for PLL to stabilize. + + pllc4_enabled |= PLLC4_ENABLED; +} + +static void _clock_disable_pllc4(u32 mask) +{ + pllc4_enabled &= ~mask; + + // Check if currently in use or disabled. + if ((pllc4_enabled & PLLC4_IN_USE) || !(pllc4_enabled & PLLC4_ENABLED)) + return; + + // Disable PLLC4. + msleep(1); // Wait at least 1ms to prevent glitching. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ; + usleep(10); + + pllc4_enabled = 0; +} + #define L_SWR_SDMMC1_RST (1 << 14) #define L_SWR_SDMMC2_RST (1 << 9) #define L_SWR_SDMMC4_RST (1 << 15) @@ -501,16 +551,32 @@ static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) divisor = 14; // 8 div. break; case 100000: - *pclock = 90667; - divisor = 7; // 4.5 div. + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + *pclock = 99840; + divisor = 2; // 2 div. break; case 164000: *pclock = 163200; divisor = 3; // 2.5 div. break; - case 200000: - *pclock = 204000; - divisor = 2; // 2 div. + case 200000: // 240MHz evo+. + switch (id) + { + case SDMMC_1: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_2: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + case SDMMC_3: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_4: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + } + *pclock = 199680; + divisor = 0; // 1 div. break; default: *pclock = 24728; @@ -520,6 +586,10 @@ static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) _clock_sdmmc_table[id].clock = val; _clock_sdmmc_table[id].real_clock = *pclock; + // Enable PLLC4 if in use by any SDMMC. + if (source) + _clock_enable_pllc4(1 << id); + // Set SDMMC legacy timeout clock. _clock_sdmmc_config_legacy_tm(); @@ -642,4 +712,5 @@ void clock_sdmmc_disable(u32 id) _clock_sdmmc_set_reset(id); _clock_sdmmc_clear_enable(id); _clock_sdmmc_is_reset(id); + _clock_disable_pllc4(1 << id); } diff --git a/source/soc/clock.h b/bdk/soc/clock.h similarity index 99% rename from source/soc/clock.h rename to bdk/soc/clock.h index a9b9f9a..bbcd482 100644 --- a/source/soc/clock.h +++ b/bdk/soc/clock.h @@ -18,7 +18,7 @@ #ifndef _CLOCK_H_ #define _CLOCK_H_ -#include "../utils/types.h" +#include /*! Clock registers. */ #define CLK_RST_CONTROLLER_RST_SOURCE 0x0 diff --git a/source/soc/fuse.c b/bdk/soc/fuse.c similarity index 96% rename from source/soc/fuse.c rename to bdk/soc/fuse.c index 04d3612..84c366d 100644 --- a/source/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -19,8 +19,8 @@ #include -#include "../soc/fuse.h" -#include "../soc/t210.h" +#include +#include #define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) @@ -60,6 +60,14 @@ u32 fuse_read_odm(u32 idx) return FUSE(FUSE_RESERVED_ODMX(idx)); } +u32 fuse_read_odm_keygen_rev() +{ + if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) + return (fuse_read_odm(2) & 0x1F); + + return 0; +} + void fuse_wait_idle() { u32 ctrl; diff --git a/source/soc/fuse.h b/bdk/soc/fuse.h similarity index 97% rename from source/soc/fuse.h rename to bdk/soc/fuse.h index 00ee63c..e5ca2fb 100644 --- a/source/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -19,7 +19,7 @@ #ifndef _FUSE_H_ #define _FUSE_H_ -#include "../utils/types.h" +#include /*! Fuse registers. */ #define FUSE_CTRL 0x0 @@ -77,6 +77,7 @@ void fuse_disable_program(); u32 fuse_read_odm(u32 idx); +u32 fuse_read_odm_keygen_rev(); void fuse_wait_idle(); int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); diff --git a/source/soc/gpio.c b/bdk/soc/gpio.c similarity index 91% rename from source/soc/gpio.c rename to bdk/soc/gpio.c index 9183a04..281e867 100644 --- a/source/soc/gpio.c +++ b/bdk/soc/gpio.c @@ -15,9 +15,8 @@ * along with this program. If not, see . */ -#include "gpio.h" -#include "irq.h" -#include "t210.h" +#include +#include #define GPIO_BANK_IDX(port) (port >> 2) @@ -37,9 +36,18 @@ #define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2)) #define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_IRQ_BANK1 32 +#define GPIO_IRQ_BANK2 33 +#define GPIO_IRQ_BANK3 34 +#define GPIO_IRQ_BANK4 35 +#define GPIO_IRQ_BANK5 55 +#define GPIO_IRQ_BANK6 87 +#define GPIO_IRQ_BANK7 89 +#define GPIO_IRQ_BANK8 125 + static u8 gpio_bank_irq_ids[8] = { - IRQ_GPIO1, IRQ_GPIO2, IRQ_GPIO3, IRQ_GPIO4, - IRQ_GPIO5, IRQ_GPIO6, IRQ_GPIO7, IRQ_GPIO8 + GPIO_IRQ_BANK1, GPIO_IRQ_BANK2, GPIO_IRQ_BANK3, GPIO_IRQ_BANK4, + GPIO_IRQ_BANK5, GPIO_IRQ_BANK6, GPIO_IRQ_BANK7, GPIO_IRQ_BANK8 }; void gpio_config(u32 port, u32 pins, int mode) diff --git a/source/soc/gpio.h b/bdk/soc/gpio.h similarity index 98% rename from source/soc/gpio.h rename to bdk/soc/gpio.h index a7f999d..99aed88 100644 --- a/source/soc/gpio.h +++ b/bdk/soc/gpio.h @@ -18,7 +18,7 @@ #ifndef _GPIO_H_ #define _GPIO_H_ -#include "../utils/types.h" +#include #define GPIO_MODE_SPIO 0 #define GPIO_MODE_GPIO 1 diff --git a/source/soc/hw_init.c b/bdk/soc/hw_init.c similarity index 90% rename from source/soc/hw_init.c rename to bdk/soc/hw_init.c index 8867ff2..7b7ca04 100644 --- a/source/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -17,26 +17,32 @@ #include -#include "hw_init.h" -#include "bpmp.h" -#include "clock.h" -#include "fuse.h" -#include "gpio.h" -#include "i2c.h" -#include "pinmux.h" -#include "pmc.h" -#include "t210.h" -#include "../gfx/di.h" -#include "../mem/mc.h" -#include "../mem/minerva.h" -#include "../mem/sdram.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../storage/nx_sd.h" -#include "../storage/sdmmc.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include extern boot_cfg_t b_cfg; extern volatile nyx_storage_t *nyx_str; @@ -101,7 +107,7 @@ void _config_gpios() pinmux_config_i2c(I2C_1); pinmux_config_i2c(I2C_5); - pinmux_config_uart(0); + pinmux_config_uart(UART_A); // Configure volume up/down as inputs. gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO); @@ -202,10 +208,10 @@ void _config_se_brom() se_aes_key_set(14, sbk, 0x10); // Lock SBK from being read. - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E; + se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); // Lock SSK (although it's not set and unused anyways). - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; + se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); } // This memset needs to happen here, else TZRAM will behave weirdly later on. @@ -257,14 +263,14 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | @@ -294,6 +300,11 @@ void config_hw() APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; _config_gpios(); +#ifdef DEBUG_UART_PORT + clock_enable_uart(DEBUG_UART_PORT); + uart_init(DEBUG_UART_PORT, 115200); +#endif + clock_enable_cl_dvfs(); clock_enable_i2c(I2C_1); @@ -304,6 +315,9 @@ void config_hw() i2c_init(I2C_1); i2c_init(I2C_5); + // Enable charger in case it's disabled. + bq24193_enable_charger(); + _config_regulators(); _config_pmc_scratch(); // Missing from 4.x+ @@ -321,15 +335,27 @@ void config_hw() void reconfig_hw_workaround(bool extra_reconfig, u32 magic) { - // Flush and disable MMU. - bpmp_mmu_disable(); + // Disable BPMP max clock. bpmp_clk_rate_set(BPMP_CLK_NORMAL); + +#ifdef NYX + // Deinit touchscreen, 5V regulators and Joy-Con. + touch_power_off(); + set_fan_duty(0); + jc_deinit(); + regulator_disable_5v(REGULATOR_5V_ALL); + clock_disable_uart(UART_B); + clock_disable_uart(UART_C); +#endif + + // Flush/disable MMU cache and set DRAM clock to 204MHz. + bpmp_mmu_disable(); minerva_change_freq(FREQ_204); nyx_str->mtc_cfg.init_done = 0; // Re-enable clocks to Audio Processing Engine as a workaround to hanging. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. if (extra_reconfig) { @@ -352,7 +378,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) if (magic == 0xBAADF00D) { CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); - sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0); + sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0); clock_disable_cl_dvfs(); msleep(200); diff --git a/source/soc/hw_init.h b/bdk/soc/hw_init.h similarity index 96% rename from source/soc/hw_init.h rename to bdk/soc/hw_init.h index b92814b..d19f271 100644 --- a/source/soc/hw_init.h +++ b/bdk/soc/hw_init.h @@ -18,7 +18,7 @@ #ifndef _HW_INIT_H_ #define _HW_INIT_H_ -#include "../utils/types.h" +#include void config_hw(); void reconfig_hw_workaround(bool extra_reconfig, u32 magic); diff --git a/source/soc/i2c.c b/bdk/soc/i2c.c similarity index 98% rename from source/soc/i2c.c rename to bdk/soc/i2c.c index 40ab097..d3f31e7 100644 --- a/source/soc/i2c.c +++ b/bdk/soc/i2c.c @@ -17,8 +17,8 @@ #include -#include "i2c.h" -#include "../utils/util.h" +#include +#include static const u32 i2c_addrs[] = { 0x7000C000, 0x7000C400, 0x7000C500, diff --git a/source/soc/i2c.h b/bdk/soc/i2c.h similarity index 98% rename from source/soc/i2c.h rename to bdk/soc/i2c.h index 4f04bac..a630b15 100644 --- a/source/soc/i2c.h +++ b/bdk/soc/i2c.h @@ -18,7 +18,7 @@ #ifndef _I2C_H_ #define _I2C_H_ -#include "../utils/types.h" +#include #define I2C_1 0 #define I2C_2 1 diff --git a/source/soc/irq.c b/bdk/soc/irq.c similarity index 98% rename from source/soc/irq.c rename to bdk/soc/irq.c index 627976d..cb34d12 100644 --- a/source/soc/irq.c +++ b/bdk/soc/irq.c @@ -19,9 +19,9 @@ #include #include "irq.h" -#include "t210.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" +#include +#include +#include //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) diff --git a/source/soc/irq.h b/bdk/soc/irq.h similarity index 99% rename from source/soc/irq.h rename to bdk/soc/irq.h index c77d980..d33ffbe 100644 --- a/source/soc/irq.h +++ b/bdk/soc/irq.h @@ -19,7 +19,7 @@ #ifndef IRQ_H #define IRQ_H -#include "../utils/types.h" +#include #define IRQ_MAX_HANDLERS 16 diff --git a/source/soc/kfuse.c b/bdk/soc/kfuse.c similarity index 87% rename from source/soc/kfuse.c rename to bdk/soc/kfuse.c index f2fde5a..2da9593 100644 --- a/source/soc/kfuse.c +++ b/bdk/soc/kfuse.c @@ -14,12 +14,9 @@ * along with this program. If not, see . */ -#include "../soc/kfuse.h" -#include "../soc/clock.h" -#include "../soc/t210.h" - -#pragma GCC push_options -#pragma GCC optimize ("Os") +#include +#include +#include int kfuse_wait_ready() { @@ -48,9 +45,7 @@ int kfuse_read(u32 *buf) res = 1; -out:; +out: clock_disable_kfuse(); return res; } - -#pragma GCC pop_options diff --git a/source/soc/kfuse.h b/bdk/soc/kfuse.h similarity index 97% rename from source/soc/kfuse.h rename to bdk/soc/kfuse.h index a535803..099dcac 100644 --- a/source/soc/kfuse.h +++ b/bdk/soc/kfuse.h @@ -17,7 +17,7 @@ #ifndef _KFUSE_H_ #define _KFUSE_H_ -#include "../utils/types.h" +#include #define KFUSE_STATE_SOFTRESET (1 << 31) #define KFUSE_STATE_STOP (1 << 25) diff --git a/source/soc/pinmux.c b/bdk/soc/pinmux.c similarity index 95% rename from source/soc/pinmux.c rename to bdk/soc/pinmux.c index 582ab29..2601cdf 100644 --- a/source/soc/pinmux.c +++ b/bdk/soc/pinmux.c @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#include "../soc/pinmux.h" -#include "../soc/t210.h" +#include +#include void pinmux_config_uart(u32 idx) { diff --git a/source/soc/pinmux.h b/bdk/soc/pinmux.h similarity index 99% rename from source/soc/pinmux.h rename to bdk/soc/pinmux.h index ca57584..9a3ed5c 100644 --- a/source/soc/pinmux.h +++ b/bdk/soc/pinmux.h @@ -17,7 +17,7 @@ #ifndef _PINMUX_H_ #define _PINMUX_H_ -#include "../utils/types.h" +#include /*! APB MISC registers. */ #define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 diff --git a/source/soc/pmc.h b/bdk/soc/pmc.h similarity index 100% rename from source/soc/pmc.h rename to bdk/soc/pmc.h diff --git a/source/soc/pmc_lp0_t210.h b/bdk/soc/pmc_lp0_t210.h similarity index 99% rename from source/soc/pmc_lp0_t210.h rename to bdk/soc/pmc_lp0_t210.h index 641d9f7..5b87d5a 100644 --- a/source/soc/pmc_lp0_t210.h +++ b/bdk/soc/pmc_lp0_t210.h @@ -14,7 +14,7 @@ #ifndef _TEGRA210_PMC_H_ #define _TEGRA210_PMC_H_ -#include "../utils/types.h" +#include struct tegra_pmc_regs { diff --git a/source/soc/t210.h b/bdk/soc/t210.h similarity index 98% rename from source/soc/t210.h rename to bdk/soc/t210.h index b45ef2a..78432c1 100644 --- a/source/soc/t210.h +++ b/bdk/soc/t210.h @@ -17,7 +17,7 @@ #ifndef _T210_H_ #define _T210_H_ -#include "../utils/types.h" +#include #define BOOTROM_BASE 0x100000 #define IRAM_BASE 0x40000000 @@ -162,6 +162,8 @@ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_PINMUX_GLOBAL 0x40 #define APB_MISC_GP_HIDREV 0x804 +#define GP_HIDREV_MAJOR_T210 0x1 +#define GP_HIDREV_MAJOR_T210B01 0x2 #define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 diff --git a/bdk/soc/uart.c b/bdk/soc/uart.c new file mode 100644 index 0000000..75e18b8 --- /dev/null +++ b/bdk/soc/uart.c @@ -0,0 +1,169 @@ +/* +* 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 . +*/ + +#include +#include +#include +#include + +/* 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() + 250; + u32 i; + + for (i = 0; ; i++) + { + while (!(uart->UART_LSR & UART_LSR_RDR)) + { + if (timeout < get_tmr_us()) + break; + if (len && len < i) + break; + } + if (timeout < get_tmr_us()) + break; + + buf[i] = uart->UART_THR_DLAB; + timeout = get_tmr_us() + 250; + } + + 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); + } + } +} diff --git a/bdk/soc/uart.h b/bdk/soc/uart.h new file mode 100644 index 0000000..809192a --- /dev/null +++ b/bdk/soc/uart.h @@ -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 . +*/ + +#ifndef _UART_H_ +#define _UART_H_ + +#include + +#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 diff --git a/source/storage/mbr_gpt.h b/bdk/storage/mbr_gpt.h similarity index 98% rename from source/storage/mbr_gpt.h rename to bdk/storage/mbr_gpt.h index 923b6d2..9e0e97d 100644 --- a/source/storage/mbr_gpt.h +++ b/bdk/storage/mbr_gpt.h @@ -18,7 +18,7 @@ #ifndef MBR_GPT_H #define MBR_GPT_H -#include "../utils/types.h" +#include typedef struct _mbr_chs_t { diff --git a/source/storage/mmc.h b/bdk/storage/mmc.h similarity index 100% rename from source/storage/mmc.h rename to bdk/storage/mmc.h diff --git a/source/storage/nx_sd.h b/bdk/storage/nx_sd.h similarity index 78% rename from source/storage/nx_sd.h rename to bdk/storage/nx_sd.h index 22e5f3b..bc4c2d4 100644 --- a/source/storage/nx_sd.h +++ b/bdk/storage/nx_sd.h @@ -18,9 +18,9 @@ #ifndef NX_SD_H #define NX_SD_H -#include "sdmmc.h" -#include "sdmmc_driver.h" -#include "../libs/fatfs/ff.h" +#include +#include +#include enum { @@ -28,17 +28,29 @@ enum SD_1BIT_HS25 = 1, SD_4BIT_HS25 = 2, SD_UHS_SDR82 = 3, + SD_UHS_SDR104 = 4 +}; + +enum +{ + SD_ERROR_INIT_FAIL = 0, + SD_ERROR_RW_FAIL = 1, + SD_ERROR_RW_RETRY = 2 }; extern sdmmc_t sd_sdmmc; extern sdmmc_storage_t sd_storage; extern FATFS sd_fs; +void sd_error_count_increment(u8 type); +u16 *sd_get_error_count(); +bool sd_get_card_removed(); 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_end(); void *sd_file_read(const char *path, u32 *fsize); int sd_save_to_file(void *buf, u32 size, const char *filename); diff --git a/bdk/storage/ramdisk.c b/bdk/storage/ramdisk.c new file mode 100644 index 0000000..e7b7c01 --- /dev/null +++ b/bdk/storage/ramdisk.c @@ -0,0 +1,67 @@ +/* + * Ramdisk 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 . + */ + +#include + +#include "ramdisk.h" +#include +#include + +#include + +int ram_disk_init(FATFS *ram_fs) +{ + int res; + u8 *buf = malloc(0x400000); + + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + + res = f_mkfs("ram:", FM_EXFAT, RAMDISK_CLUSTER_SZ, buf, 0x400000); // Format as exFAT w/ 32KB cluster. + if (!res) + res = f_mount(ram_fs, "ram:", 1); // Mount ramdisk. + + free(buf); + + return res; +} + +int ram_disk_read(u32 sector, u32 sector_count, void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + return 1; + + memcpy(buf, (void *)sector_off, bytes_count); + + return 0; +} + +int ram_disk_write(u32 sector, u32 sector_count, const void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + return 1; + + memcpy((void *)sector_off, buf, bytes_count); + + return 0; +} diff --git a/bdk/storage/ramdisk.h b/bdk/storage/ramdisk.h new file mode 100644 index 0000000..ef43bb5 --- /dev/null +++ b/bdk/storage/ramdisk.h @@ -0,0 +1,30 @@ +/* + * Ramdisk 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 . + */ + +#ifndef RAM_DISK_H +#define RAM_DISK_H + +#include + +#define RAMDISK_CLUSTER_SZ 32768 + +int ram_disk_init(FATFS *ram_fs); +int ram_disk_read(u32 sector, u32 sector_count, void *buf); +int ram_disk_write(u32 sector, u32 sector_count, const void *buf); + +#endif \ No newline at end of file diff --git a/source/storage/sd.h b/bdk/storage/sd.h similarity index 98% rename from source/storage/sd.h rename to bdk/storage/sd.h index 3ecfc07..a780ec8 100644 --- a/source/storage/sd.h +++ b/bdk/storage/sd.h @@ -1,6 +1,4 @@ /* - * include/linux/mmc/sd.h - * * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (c) 2018 CTCaer * @@ -10,8 +8,8 @@ * your option) any later version. */ -#ifndef LINUX_MMC_SD_H -#define LINUX_MMC_SD_H +#ifndef MMC_SD_H +#define MMC_SD_H /* SD commands type argument response */ /* class 0 */ diff --git a/source/storage/sdmmc.c b/bdk/storage/sdmmc.c similarity index 98% rename from source/storage/sdmmc.c rename to bdk/storage/sdmmc.c index 902d0ca..fc41458 100644 --- a/source/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -16,18 +16,20 @@ */ #include -#include "sdmmc.h" -#include "mmc.h" -#include "nx_sd.h" -#include "sd.h" -#include "../../common/memory_map.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include +#include +#include +#include //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) +u32 sd_power_cycle_time_start; + static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) { const u32 mask = (size < 32 ? 1 << size : 0) - 1; @@ -187,6 +189,8 @@ reinit_try: else retries--; + sd_error_count_increment(SD_ERROR_RW_RETRY); + msleep(50); } while (retries); @@ -194,10 +198,17 @@ reinit_try: if (storage->sdmmc->id == SDMMC_1) { int res; + + sd_error_count_increment(SD_ERROR_RW_FAIL); + if (!first_reinit) res = sd_initialize(true); else + { res = sd_init_retry(true); + if (!res) + sd_error_count_increment(SD_ERROR_INIT_FAIL); + } retries = 3; first_reinit = true; diff --git a/source/storage/sdmmc.h b/bdk/storage/sdmmc.h similarity index 97% rename from source/storage/sdmmc.h rename to bdk/storage/sdmmc.h index aacc26a..6bfad77 100644 --- a/source/storage/sdmmc.h +++ b/bdk/storage/sdmmc.h @@ -18,8 +18,8 @@ #ifndef _SDMMC_H_ #define _SDMMC_H_ -#include "../utils/types.h" -#include "sdmmc_driver.h" +#include +#include extern u32 sd_power_cycle_time_start; diff --git a/source/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c similarity index 95% rename from source/storage/sdmmc_driver.c rename to bdk/storage/sdmmc_driver.c index 8e32f5d..557fe8d 100644 --- a/source/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -17,22 +17,26 @@ #include -#include "mmc.h" -#include "sdmmc.h" -#include "../gfx/gfx.h" -#include "../power/max7762x.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //#define DPRINTF(...) gfx_printf(__VA_ARGS__) +//#define ERROR_EXTRA_PRINTING #define DPRINTF(...) -u32 sd_power_cycle_time_start; +#ifdef NYX +#define ERROR_EXTRA_PRINTING +#define SDMMC_EMMC_OC +#endif /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { @@ -222,7 +226,11 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } +#ifdef SDMMC_EMMC_OC +static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc, bool overclock) +#else static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) +#endif { int result = 1, should_disable_sd_clock = 0; @@ -232,6 +240,11 @@ static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } +#ifdef SDMMC_EMMC_OC + if (sdmmc->id == SDMMC_4 && overclock) + sdmmc->regs->vendllcalcfg = sdmmc->regs->vendllcalcfg &= 0xFFFFC07F | (0x7C << 7); // Add -4 TX_DLY_CODE_OFFSET if HS533. +#endif + sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE; _sdmmc_get_clkcon(sdmmc); @@ -345,7 +358,15 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; if (type == SDHCI_TIMING_MMC_HS400) + { +#ifdef SDMMC_EMMC_OC + bool overclock_en = clock > 208000; + return _sdmmc_dll_cal_execute(sdmmc, overclock_en); +#else return _sdmmc_dll_cal_execute(sdmmc); +#endif + } + return 1; } @@ -906,7 +927,9 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) } if (result != SDMMC_MASKINT_NOERROR) { - DPRINTF("%08X!\n", result); +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("%08X!", result); +#endif _sdmmc_reset(sdmmc); return 0; } @@ -929,7 +952,9 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ { if (!_sdmmc_config_dma(sdmmc, &blkcnt, req)) { - DPRINTF("SDMMC: DMA Wrong cfg!\n"); +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: DMA Wrong cfg!"); +#endif return 0; } @@ -945,14 +970,18 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ if (!_sdmmc_send_cmd(sdmmc, cmd, is_data_present)) { - DPRINTF("SDMMC: Wrong Response type %08X!\n", cmd->rsp_type); +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC: Wrong Response type %08X!", cmd->rsp_type); +#endif return 0; } int result = _sdmmc_wait_response(sdmmc); if (!result) { - DPRINTF("SDMMC: Transfer timeout!\n"); +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: Transfer timeout!"); +#endif } DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); @@ -964,7 +993,9 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); if (!result) { - DPRINTF("SDMMC: Unknown response %08X!\n", sdmmc->rsp[0]); +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC: Unknown response %08X!", sdmmc->rsp[0]); +#endif } } if (req && result) @@ -972,7 +1003,9 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ result = _sdmmc_update_dma(sdmmc); if (!result) { - DPRINTF("SDMMC: DMA Update failed!\n"); +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: DMA Update failed!"); +#endif } } } @@ -998,7 +1031,9 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ result = _sdmmc_wait_card_busy(sdmmc); if (!result) { - DPRINTF("SDMMC: Busy timeout!\n"); +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: Busy timeout!"); +#endif } return result; } diff --git a/source/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h similarity index 99% rename from source/storage/sdmmc_driver.h rename to bdk/storage/sdmmc_driver.h index 736faa8..2937d93 100644 --- a/source/storage/sdmmc_driver.h +++ b/bdk/storage/sdmmc_driver.h @@ -18,8 +18,8 @@ #ifndef _SDMMC_DRIVER_H_ #define _SDMMC_DRIVER_H_ -#include "../utils/types.h" -#include "sdmmc_t210.h" +#include +#include /*! SDMMC controller IDs. */ #define SDMMC_1 0 diff --git a/source/storage/sdmmc_t210.h b/bdk/storage/sdmmc_t210.h similarity index 98% rename from source/storage/sdmmc_t210.h rename to bdk/storage/sdmmc_t210.h index eb17714..c5ecf11 100644 --- a/source/storage/sdmmc_t210.h +++ b/bdk/storage/sdmmc_t210.h @@ -18,7 +18,7 @@ #ifndef _SDMMC_T210_H_ #define _SDMMC_T210_H_ -#include "../utils/types.h" +#include #define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000 #define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000 diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c new file mode 100644 index 0000000..686f9e8 --- /dev/null +++ b/bdk/thermal/fan.c @@ -0,0 +1,106 @@ +/* + * Fan driver for Nintendo Switch + * + * Copyright (c) 2018-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 . + */ + +#include +#include +#include +#include +#include +#include + +void set_fan_duty(u32 duty) +{ + static bool fan_init = false; + static u16 curr_duty = -1; + + if (curr_duty == duty) + return; + + if (!fan_init) + { + // Fan tachometer. + PINMUX_AUX(PINMUX_AUX_CAM1_PWDN) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; + gpio_config(GPIO_PORT_S, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_S, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); + + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Max PWM to disable fan. + + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + gpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode. + + fan_init = true; + } + + if (duty > 236) + duty = 236; + + // Inverted polarity. + u32 inv_duty = 236 - duty; + + // If disabled send a 0 duty. + if (inv_duty == 236) + { + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Bit 24 is absolute 0%. + regulator_disable_5v(REGULATOR_5V_FAN); + + // Disable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = + PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_DOWN; // Set source to PWM1. + } + else // Set PWM duty. + { + // Fan power supply. + regulator_enable_5v(REGULATOR_5V_FAN); + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16); + + // Enable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + } + + curr_duty = duty; +} + +void get_fan_speed(u32 *duty, u32 *rpm) +{ + if (rpm) + { + u32 irq_count = 1; + bool should_read = true; + bool irq_val = 0; + + // Poll irqs for 2 seconds. + int timer = get_tmr_us() + 1000000; + while (timer - get_tmr_us()) + { + irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); + if (irq_val && should_read) + { + irq_count++; + should_read = false; + } + else if (!irq_val) + should_read = true; + } + + // Calculate rpm based on triggered interrupts. + *rpm = 60000000 / ((1000000 * 2) / irq_count); + } + + if (duty) + *duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF); +} diff --git a/bdk/thermal/fan.h b/bdk/thermal/fan.h new file mode 100644 index 0000000..e827975 --- /dev/null +++ b/bdk/thermal/fan.h @@ -0,0 +1,29 @@ +/* + * Fan driver for Nintendo Switch + * + * 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 . + */ + +#ifndef __FAN_H_ +#define __FAN_H_ + +#include + +// Disable: 0 (0 RPM), min duty: 1 (960 RPM), max duty 235 (11000 RPM). +void set_fan_duty(u32 duty); +// Passing NULL ptr on either of the two, disables parsing of it. +void get_fan_speed(u32 *duty, u32 *rpm); + +#endif /* __FAN_H_ */ diff --git a/bdk/thermal/tmp451.c b/bdk/thermal/tmp451.c new file mode 100644 index 0000000..fb9f9fa --- /dev/null +++ b/bdk/thermal/tmp451.c @@ -0,0 +1,65 @@ +/* + * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 + * + * 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 . + */ + +#include +#include + +u16 tmp451_get_soc_temp(bool intenger) +{ + u8 val; + u16 temp = 0; + + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TEMP_REG); + if (intenger) + return val; + + temp = val << 8; + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_DEC_REG); + temp |= ((val >> 4) * 625) / 100; + + return temp; +} + +u16 tmp451_get_pcb_temp(bool intenger) +{ + u8 val; + u16 temp = 0; + + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TEMP_REG); + if (intenger) + return val; + + temp = val << 8; + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TMP_DEC_REG); + temp |= ((val >> 4) * 625) / 100; + + return temp; +} + +void tmp451_init() +{ + // Disable ALARM and Range to 0 - 127 oC. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0x80); + + // Set conversion rate to 32/s and make a read to update the reg. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 9); + tmp451_get_soc_temp(false); + + // Set rate to every 4 seconds. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 2); +} diff --git a/bdk/thermal/tmp451.h b/bdk/thermal/tmp451.h new file mode 100644 index 0000000..9549ffa --- /dev/null +++ b/bdk/thermal/tmp451.h @@ -0,0 +1,42 @@ +/* + * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 + * + * 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 . + */ + +#ifndef __TMP451_H_ +#define __TMP451_H_ + +#include + +#define TMP451_I2C_ADDR 0x4C + +#define TMP451_PCB_TEMP_REG 0x00 +#define TMP451_SOC_TEMP_REG 0x01 + +#define TMP451_CONFIG_REG 0x09 +#define TMP451_CNV_RATE_REG 0x0A + +#define TMP451_SOC_TMP_DEC_REG 0x10 +#define TMP451_PCB_TMP_DEC_REG 0x15 + +// If input is false, the return value is packed. MSByte is the integer in oC +// and the LSByte is the decimal point truncated to 2 decimal places. +// Otherwise it's an integer oC. +u16 tmp451_get_soc_temp(bool integer); +u16 tmp451_get_pcb_temp(bool integer); +void tmp451_init(); + +#endif /* __TMP451_H_ */ diff --git a/bdk/usb/usb_descriptors.h b/bdk/usb/usb_descriptors.h new file mode 100644 index 0000000..74556f8 --- /dev/null +++ b/bdk/usb/usb_descriptors.h @@ -0,0 +1,752 @@ +/* + * USB 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 . + */ + +#ifndef _USB_DESCRIPTORS_H_ +#define _USB_DESCRIPTORS_H_ + +#include + +typedef enum { + USB_DESCRIPTOR_DEVICE = 1, + USB_DESCRIPTOR_CONFIGURATION = 2, + USB_DESCRIPTOR_STRING = 3, + USB_DESCRIPTOR_INTERFACE = 4, + USB_DESCRIPTOR_ENDPOINT = 5, + USB_DESCRIPTOR_DEVICE_QUALIFIER = 6, + USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + USB_DESCRIPTOR_INTERFACE_POWER = 8, + USB_DESCRIPTOR_INTERFACE_OTG = 9, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT = 15, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP = 16, + USB_DESCRIPTOR_HID = 33, + USB_DESCRIPTOR_HID_REPORT = 34 +} usb_desc_type_t; + +typedef enum { + USB_DESCRIPTOR_MS_COMPAT_ID = 4, + USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5 +} usb_vendor_desc_type_t; + +typedef enum { + USB_ATTR_REMOTE_WAKE_UP = 0x20, + USB_ATTR_SELF_POWERED = 0x40, + USB_ATTR_BUS_POWERED_RSVD = 0x80 +} usb_cfg_attr_type_t; + +typedef enum +{ + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISO = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INTR = 3 +} usb_cfg_ep_type_t; + +/* Device descriptor structure */ +typedef struct _usb_dev_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u16 idVendor; // Vendor ID assigned by USB forum. + u16 idProduct; // Product ID assigned by Organization. + u16 bcdDevice; // Device Release number in BCD. + u8 iManufacturer; // Index of String descriptor describing Manufacturer. + u8 iProduct; // Index of String descriptor describing Product. + u8 iSerialNumber; // Index of String descriptor describing Serial number. + u8 bNumConfigs; // Number of possible configuration. +} __attribute__((packed)) usb_dev_descr_t; + +/* Device Qualigier descriptor structure */ +typedef struct _usb_dev_qual_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u8 bNumOtherConfigs; // Number of possible other-speed configurations. + u8 bReserved; // Reserved for future use, must be zero +} __attribute__((packed)) usb_dev_qual_descr_t; + +/* Configuration descriptor structure */ +typedef struct _usb_cfg_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + u16 wTotalLength; // Total length of all descriptors for this configuration. + u8 bNumInterfaces; // Number of interfaces in this configuration. + u8 bConfigurationValue; // Value of this configuration (1 based). + u8 iConfiguration; // Index of String Descriptor describing the configuration. + u8 bmAttributes; // Configuration characteristics. + u8 bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) usb_cfg_descr_t; + +/* Interface descriptor structure */ +typedef struct _usb_inter_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + u8 bInterfaceNumber; // Number of this interface (0 based). + u8 bAlternateSetting; // Value of this alternate interface setting. + u8 bNumEndpoints; // Number of endpoints in this interface. + u8 bInterfaceClass; // Class code (assigned by the USB-IF). + u8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + u8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF). + u8 iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) usb_inter_descr_t; + +/* HID descriptor structure */ +typedef struct _usb_hid_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_HID). + u16 bcdHID; // HID class specification release + u8 bCountryCode; // Country code. + u8 bNumDescriptors; // Number of descriptors. + u8 bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT). + u16 bDescriptorLength; // Report descriptor length. +} __attribute__((packed)) usb_hid_descr_t; + +/* Endpoint descriptor structure */ +typedef struct _usb_ep_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + u8 bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN). + u8 bmAttributes; // Endpoint transfer type. + u16 wMaxPacketSize; // Maximum packet size. + u8 bInterval; // Polling interval in frames. For Interrupt and Isochronous data transfer only. +} __attribute__((packed)) usb_ep_descr_t; + +typedef struct _usb_cfg_simple_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_simple_descr_t; + +typedef struct _usb_cfg_hid_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_hid_descr_t hid; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_hid_descr_t; + +typedef struct _usb_dev_bot_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT) + u16 wTotalLength; // Size of this descriptor in bytes. + u8 bNumDeviceCaps; // Number of device capabilities in this descriptor. + + /* Device Capability USB 2.0 Extension Descriptor */ + /* Needed for a USB2.10 device. */ + u8 bLengthCap0; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap0; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap0; // USB2: 2. + u32 bmAttributesCap0; // bit1: Link Power Management (LPM). + + u8 bLengthCap1; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap1; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap1; // USB3: 3. + u8 bmAttributesCap1; // bit1: Latency Tolerance Messaging (LTM). + u16 wSpeedsSupported; // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed. + u8 bFunctionalitySupport; // Lowest speed at which all the functionality is available. 1: Full speed and above. + u8 bU1DevExitLat; // USB3.0 U1 exit latency. + u16 wU2DevExitLat; // USB3.0 U2 exit latency. + +} __attribute__((packed)) usb_dev_bot_t; + +/* Microsoft OS String descriptor structure */ +typedef struct _usb_ms_os_descr_t +{ + u8 bLength; // 0x12 + u8 bDescriptorType; // 3 + u16 wSignature[7]; // "MSFT100" UTF16 LE + u8 bVendorCode; // + u8 bPadding; +} __attribute__((packed)) usb_ms_os_descr_t; + +/* Microsoft Compatible ID Feature descriptor structure */ +typedef struct _usb_ms_cid_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wCompatibilityId; + u8 bSections; + u8 bReserved0[7]; + u8 bInterfaceNumber; + u8 bReserved1; + u8 bCompatibleId[8]; + u8 bSubCompatibleId[8]; + u8 bReserved2[6]; +} __attribute__((packed)) usb_ms_cid_descr_t; + +/* Microsoft Extended Properties Feature descriptor structure */ +typedef struct _usb_ms_ext_prop_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wExtendedProperty; + u16 wSections; + u32 dPropertySize; + u32 dPropertyType; + u16 wPropertyNameLength; + u16 wPropertyName[22]; // UTF16 LE + u32 dPropertyDataLength; + u16 wPropertyData[2]; // UTF16 LE +} __attribute__((packed)) usb_ms_ext_prop_descr_t; + +typedef struct _usb_desc_t +{ + usb_dev_descr_t *dev; + usb_dev_qual_descr_t *dev_qual; + usb_cfg_simple_descr_t *cfg; + usb_cfg_simple_descr_t *cfg_other; + usb_dev_bot_t *dev_bot; + u8 *vendor; + u8 *product; + usb_ms_os_descr_t *ms_os; + usb_ms_cid_descr_t *ms_cid; + usb_ms_ext_prop_descr_t *mx_ext; +} usb_desc_t; + +usb_dev_descr_t usb_device_descriptor_ums = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E0, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_dev_qual_descr_t usb_device_qualifier_descriptor = +{ + .bLength = 10, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .bNumOtherConfigs = 0x01, + .bReserved = 0x00 +}; + +usb_cfg_simple_descr_t usb_configuration_descriptor_ums = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 0x00, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 0x00 +}; + +usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = +{ + /* Other Speed Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0x00, + .interface.bAlternateSetting = 0x00, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x40, + .endpoint[0].bInterval = 0, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x40, + .endpoint[1].bInterval = 0 +}; + +usb_dev_bot_t usb_device_binary_object_descriptor = +{ + .bLength = 5, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT, + .wTotalLength = 22, + .bNumDeviceCaps = 2, + + /* Device Capability USB 2.0 Extension Descriptor */ + .bLengthCap0 = 7, + .bDescriptorTypeCap0 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap0 = 2, // USB2. + .bmAttributesCap0 = 0, + + /* Device Capability SuperSpeed Descriptor */ + /* Needed for a USB2.10 device. */ + .bLengthCap1 = 10, + .bDescriptorTypeCap1 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap1 = 3, // USB3. + .bmAttributesCap1 = 0, + .wSpeedsSupported = 0x6, // FS | HS. + .bFunctionalitySupport = 1, // FS and above. + .bU1DevExitLat = 0, + .wU2DevExitLat = 0 +}; + +u8 usb_vendor_string_descriptor_ums[32] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0, + 'D', 0, 'i', 0, 's', 0, 'k', 0 +}; + +u8 usb_product_string_descriptor_ums[22] = +{ + 8, 0x03, + 'U', 0, 'M', 0, 'S', 0 +}; + +usb_ms_os_descr_t usb_ms_os_descriptor = +{ + .bLength = 0x28, + .bDescriptorType = 0x03, + .wSignature[0] = 'M', + .wSignature[1] = 'S', + .wSignature[2] = 'F', + .wSignature[3] = 'T', + .wSignature[4] = '1', + .wSignature[5] = '0', + .wSignature[6] = '0', + .bVendorCode = 0x99, +}; + +usb_ms_cid_descr_t usb_ms_cid_descriptor = +{ + .dLength = 0x28, + .wVersion = 0x100, + .wCompatibilityId = USB_DESCRIPTOR_MS_COMPAT_ID, + .bSections = 1, + .bInterfaceNumber = 0, + .bReserved1 = 1, + + .bCompatibleId[0] = 'N', + .bCompatibleId[1] = 'Y', + .bCompatibleId[2] = 'X', + .bCompatibleId[3] = 'U', + .bCompatibleId[4] = 'S', + .bCompatibleId[5] = 'B', +}; + +usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = +{ + .dLength = 0x48, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 1, + + .dPropertySize = 0x3E, + .dPropertyType = 4, // DWORD + + .wPropertyNameLength = 0x2C, + .wPropertyName[0] = 'M', // MaximumTransferLength. + .wPropertyName[1] = 'a', + .wPropertyName[2] = 'x', + .wPropertyName[3] = 'i', + .wPropertyName[4] = 'm', + .wPropertyName[5] = 'u', + .wPropertyName[6] = 'm', + .wPropertyName[7] = 'T', + .wPropertyName[8] = 'r', + .wPropertyName[9] = 'a', + .wPropertyName[10] = 'n', + .wPropertyName[11] = 's', + .wPropertyName[12] = 'f', + .wPropertyName[13] = 'e', + .wPropertyName[14] = 'r', + .wPropertyName[15] = 'L', + .wPropertyName[16] = 'e', + .wPropertyName[17] = 'n', + .wPropertyName[18] = 'g', + .wPropertyName[19] = 't', + .wPropertyName[20] = 'h', + .wPropertyName[21] = 0, + + .dPropertyDataLength = 0x4, + .wPropertyData[0] = 0x00, // 1MB. + .wPropertyData[1] = 0x10, +}; + +usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = +{ + .dLength = 7, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 0, +}; + +usb_dev_descr_t usb_device_descriptor_hid_jc = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E1, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_dev_descr_t usb_device_descriptor_hid_touch = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E2, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x110, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = 0x43, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. +}; + +u8 usb_vendor_string_descriptor_hid[22] = +{ + 16, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'U', 0, 'S', 0, 'B', 0 +}; + +u8 usb_product_string_descriptor_hid_jc[24] = +{ + 24, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 +}; + +u8 usb_product_string_descriptor_hid_touch[26] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 +}; + +u8 hid_report_descriptor_jc[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop), + 0x09, 0x04, // USAGE (Joystick), + 0xa1, 0x01, // COLLECTION (Application), + 0xa1, 0x02, // COLLECTION (Logical), + 0x75, 0x08, // REPORT_SIZE (8), + 0x95, 0x04, // REPORT_COUNT (4), + 0x15, 0x00, // LOGICAL_MINIMUM (0), + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255), + 0x35, 0x00, // PHYSICAL_MINIMUM (0), + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255), + 0x09, 0x30, // USAGE (X_ID), + 0x09, 0x31, // USAGE (Y_ID), + 0x09, 0x32, // USAGE (Z_ID), + 0x09, 0x35, // USAGE (Rz_ID), + 0x81, 0x02, // INPUT (IOF_Variable), + 0x75, 0x04, // REPORT_SIZE (4), + 0x95, 0x01, // REPORT_COUNT (1), + 0x25, 0x07, // LOGICAL_MAXIMUM (7), + 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315), + 0x65, 0x14, // UNIT (Eng_Rot_Angular_Pos), + 0x09, 0x39, // USAGE (Hat_Switch), + 0x81, 0x42, // INPUT (IOF_NullposVar), + 0x65, 0x00, // UNIT (Unit_None), + 0x75, 0x01, // REPORT_SIZE (1), + 0x95, 0x0c, // REPORT_COUNT (12), + 0x25, 0x01, // LOGICAL_MAXIMUM (1), + 0x45, 0x01, // PHYSICAL_MAXIMUM (1), + 0x05, 0x09, // USAGE_PAGE (Button_ID), + 0x19, 0x01, // USAGE_MINIMUM (1), + 0x29, 0x0c, // USAGE_MAXIMUM (12), + 0x81, 0x02, // INPUT (IOF_Variable), + 0xc0, // END_COLLECTION(), + 0xc0 // END_COLLECTION(), +}; + +u8 hid_report_descriptor_touch[] = +{ + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x05, // USAGE (Touch Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x05, // REPORT_ID (Touch pad) + 0x09, 0x22, // USAGE (Finger) + 0xa1, 0x02, // COLLECTION (Logical) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x42, // USAGE (Tip switch) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x15, 0x00, // LOGICAL_MINIMUM (1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x09, 0x54, // USAGE (Contact Count) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0A, // LOGICAL_MAXIMUM (10) + 0x09, 0x51, // USAGE (Contact Identifier) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // 0x15, 0x00, // LOGICAL_MINIMUM (0) + // 0x26, 0xF8, 0x2A, // LOGICAL_MAXIMUM (11000) + // 0x95, 0x01, // REPORT_COUNT (1) + // 0x75, 0x08, // REPORT_SIZE (16) + // 0x09, 0x30, // USAGE (Pressure) + // 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x01, // USAGE_PAGE (Generic Desk.. + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x04, // LOGICAL_MAXIMUM (1279) + 0x75, 0x10, // REPORT_SIZE (16) + 0x55, 0x0e, // UNIT_EXPONENT (-2) + 0x65, 0x13, // UNIT(Inch,EngLinear) + 0x09, 0x30, // USAGE (X) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xFF, 0x04, // PHYSICAL_MAXIMUM (1279) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x26, 0xCF, 0x02, // LOGICAL_MAXIMUM (719) + 0x46, 0xCF, 0x02, // PHYSICAL_MAXIMUM (719) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x0d, // USAGE PAGE (Digitizers) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; + +usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x111, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = sizeof(hid_report_descriptor_touch), + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. +}; + +usb_desc_t usb_gadget_ums_descriptors = +{ + .dev = &usb_device_descriptor_ums, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = &usb_configuration_descriptor_ums, + .cfg_other = &usb_other_speed_config_descriptor_ums, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_ums, + .product = usb_product_string_descriptor_ums, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_ums +}; + +usb_desc_t usb_gadget_hid_jc_descriptors = +{ + .dev = &usb_device_descriptor_hid_jc, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_jc, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_jc, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; + +usb_desc_t usb_gadget_hid_touch_descriptors = +{ + .dev = &usb_device_descriptor_hid_touch, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_touch, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_touch, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; + +#endif diff --git a/bdk/usb/usb_gadget_hid.c b/bdk/usb/usb_gadget_hid.c new file mode 100644 index 0000000..e26dd9a --- /dev/null +++ b/bdk/usb/usb_gadget_hid.c @@ -0,0 +1,432 @@ +/* + * USB Gadget HID driver for Tegra X1 + * + * 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 . + */ + +#include + +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +typedef struct _gamepad_report_t +{ + u8 x; + u8 y; + u8 z; + u8 rz; + + u8 hat:4; + u8 btn1:1; + u8 btn2:1; + u8 btn3:1; + u8 btn4:1; + + u8 btn5:1; + u8 btn6:1; + u8 btn7:1; + u8 btn8:1; + u8 btn9:1; + u8 btn10:1; + u8 btn11:1; + u8 btn12:1; +} __attribute__((packed)) gamepad_report_t; + +typedef struct _jc_cal_t +{ + bool cl_done; + bool cr_done; + u16 clx_max; + u16 clx_min; + u16 cly_max; + u16 cly_min; + u16 crx_max; + u16 crx_min; + u16 cry_max; + u16 cry_min; +} jc_cal_t; + +static jc_cal_t jc_cal_ctx; + +static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad) +{ + // Calibrate left stick. + if (!jc_cal_ctx.cl_done) + { + if (jc_pad->conn_l + && jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400 + && jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00) + { + jc_cal_ctx.clx_max = jc_pad->lstick_x + 0x72; + jc_cal_ctx.clx_min = jc_pad->lstick_x - 0x72; + jc_cal_ctx.cly_max = jc_pad->lstick_y + 0x72; + jc_cal_ctx.cly_min = jc_pad->lstick_y - 0x72; + jc_cal_ctx.cl_done = true; + } + else + return false; + } + + // Calibrate right stick. + if (!jc_cal_ctx.cr_done) + { + if (jc_pad->conn_r + && jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400 + && jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00) + { + jc_cal_ctx.crx_max = jc_pad->rstick_x + 0x72; + jc_cal_ctx.crx_min = jc_pad->rstick_x - 0x72; + jc_cal_ctx.cry_max = jc_pad->rstick_y + 0x72; + jc_cal_ctx.cry_min = jc_pad->rstick_y - 0x72; + jc_cal_ctx.cr_done = true; + } + else + return false; + } + + return true; +} + +static bool _jc_poll(gamepad_report_t *rpt) +{ + // Poll Joy-Con. + jc_gamepad_rpt_t *jc_pad = joycon_poll(); + + if (!jc_pad) + return false; + + // Exit emulation if Left stick and Home are pressed. + if (jc_pad->l3 && jc_pad->home) + return true; + + if (!jc_cal_ctx.cl_done || !jc_cal_ctx.cr_done) + { + if (!_jc_calibration(jc_pad)) + return false; + } + + // Re-calibrate on disconnection. + if (!jc_pad->conn_l) + jc_cal_ctx.cl_done = false; + if (!jc_pad->conn_r) + jc_cal_ctx.cr_done = false; + + // Calculate left analog stick. + if (jc_pad->lstick_x <= jc_cal_ctx.clx_max && jc_pad->lstick_x >= jc_cal_ctx.clx_min) + rpt->x = 0x7F; + else if (jc_pad->lstick_x > jc_cal_ctx.clx_max) + { + u16 x_raw = (jc_pad->lstick_x - jc_cal_ctx.clx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.clx_min - jc_pad->lstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F - x_raw; + } + + if (jc_pad->lstick_y <= jc_cal_ctx.cly_max && jc_pad->lstick_y >= jc_cal_ctx.cly_min) + rpt->y = 0x7F; + else if (jc_pad->lstick_y > jc_cal_ctx.cly_max) + { + u16 y_raw = (jc_pad->lstick_y - jc_cal_ctx.cly_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->y = 0x7F - y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cly_min - jc_pad->lstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->y = 0x7F + y_raw; + } + + // Calculate right analog stick. + if (jc_pad->rstick_x <= jc_cal_ctx.crx_max && jc_pad->rstick_x >= jc_cal_ctx.crx_min) + rpt->z = 0x7F; + else if (jc_pad->rstick_x > jc_cal_ctx.crx_max) + { + u16 x_raw = (jc_pad->rstick_x - jc_cal_ctx.crx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.crx_min - jc_pad->rstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F - x_raw; + } + + if (jc_pad->rstick_y <= jc_cal_ctx.cry_max && jc_pad->rstick_y >= jc_cal_ctx.cry_min) + rpt->rz = 0x7F; + else if (jc_pad->rstick_y > jc_cal_ctx.cry_max) + { + u16 y_raw = (jc_pad->rstick_y - jc_cal_ctx.cry_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->rz = 0x7F - y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cry_min - jc_pad->rstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->rz = 0x7F + y_raw; + } + + // Set D-pad. + switch ((jc_pad->buttons >> 16) & 0xF) + { + case 0: // none + rpt->hat = 0xF; + break; + case 1: // down + rpt->hat = 4; + break; + case 2: // up + rpt->hat = 0; + break; + case 4: // right + rpt->hat = 2; + break; + case 5: // down + right + rpt->hat = 3; + break; + case 6: // up + right + rpt->hat = 1; + break; + case 8: // left + rpt->hat = 6; + break; + case 9: // down + left + rpt->hat = 5; + break; + case 10: // up + left + rpt->hat = 7; + break; + default: + rpt->hat = 0xF; + break; + } + + // Set buttons. + rpt->btn1 = jc_pad->b; // x. + rpt->btn2 = jc_pad->a; // a. + rpt->btn3 = jc_pad->y; // b. + rpt->btn4 = jc_pad->x; // y. + + rpt->btn5 = jc_pad->l; + rpt->btn6 = jc_pad->r; + rpt->btn7 = jc_pad->zl; + rpt->btn8 = jc_pad->zr; + rpt->btn9 = jc_pad->minus; + rpt->btn10 = jc_pad->plus; + rpt->btn11 = jc_pad->l3; + rpt->btn12 = jc_pad->r3; + + //rpt->btn13 = jc_pad->cap; + //rpt->btn14 = jc_pad->home; + + return false; +} + +typedef struct _touchpad_report_t +{ + u8 rpt_id; + u8 tip_switch:1; + u8 count:7; + + u8 id; + + //u16 z; + u16 x; + u16 y; +} __attribute__((packed)) touchpad_report_t; + +static bool _fts_touch_read(touchpad_report_t *rpt) +{ + static touch_event touchpad; + + touch_poll(&touchpad); + + rpt->rpt_id = 5; + rpt->count = 1; + + // Decide touch enable. + switch (touchpad.type & STMFTS_MASK_EVENT_ID) + { + //case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 1; + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 0; + break; + case STMFTS_EV_NO_EVENT: + return false; + } + + return true; +} + +static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len) +{ + u8 status = usb_device_write_ep1_in((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, true); + + if (status == 26) + { + usbs->set_text(usbs->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(3); + } + + // Linux mitigation: If timed out, clear status. + if (status == 3) + return 0; + + return status; +} + +static bool _hid_poll_jc(usb_ctxt_t *usbs) +{ + if (_jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR)) + return true; + + // Send HID report. + if (_hid_transfer_start(usbs, sizeof(gamepad_report_t))) + return true; // EP Error. + + return false; +} + +static bool _hid_poll_touch(usb_ctxt_t *usbs) +{ + _fts_touch_read((touchpad_report_t *)USB_EP_BULK_IN_BUF_ADDR); + + // Send HID report. + if (_hid_transfer_start(usbs, sizeof(touchpad_report_t))) + return true; // EP Error. + + return false; +} + +int usb_device_gadget_hid(usb_ctxt_t *usbs) +{ + int res = 0; + u32 gadget_type; + u32 polling_time; + + if (usbs->type == USB_HID_GAMEPAD) + { + polling_time = 8000; + gadget_type = USB_GADGET_HID_GAMEPAD; + } + else + { + polling_time = 4000; + gadget_type = USB_GADGET_HID_TOUCHPAD; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_device_init()) + { + usbd_end(false, true); + return 1; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_device_ep0_initialize(gadget_type)) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for HID report request"); + + if (usb_device_get_hid_report()) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation"); + + u32 timer_sys = get_tmr_ms() + 5000; + while (true) + { + u32 timer = get_tmr_us(); + + // Parse input device. + if (usbs->type == USB_HID_GAMEPAD) + { + if (_hid_poll_jc(usbs)) + break; + } + else + { + if (_hid_poll_touch(usbs)) + break; + } + + // Check for suspended USB in case the cable was pulled. + if (usb_device_get_suspended()) + break; // Disconnected. + + // Handle control endpoint. + usbd_handle_ep0_pending_control_transfer(); + + // Wait max gadget timing. + timer = get_tmr_us() - timer; + if (timer < polling_time) + usleep(polling_time - timer); + + if (timer_sys < get_tmr_ms()) + { + usbs->system_maintenance(true); + timer_sys = get_tmr_ms() + 5000; + } + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# HID ended"); + goto exit; + +error: + usbs->set_text(usbs->label, "#C7EA46 Status:# Timed out or canceled"); + res = 1; + +exit: + usbd_end(true, false); + + return res; +} diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c new file mode 100644 index 0000000..01ab237 --- /dev/null +++ b/bdk/usb/usb_gadget_ums.c @@ -0,0 +1,1891 @@ +/* + * USB Gadget UMS driver for Tegra X1 + * + * Copyright (c) 2003-2008 Alan Stern + * Copyright (c) 2009 Samsung Electronics + * Author: Michal Nazarewicz + * 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 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +#define UMS_MAX_LUN 1 // Only 1 disk/partition for now. + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 // USBC. +#define USB_BULK_IN_FLAG 0x80 + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 // USBS. + +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +#define UMS_DISK_LBA_SHIFT 9 +#define UMS_DISK_LBA_SIZE (1 << UMS_DISK_LBA_SHIFT) + +#define UMS_DISK_MAX_IO_TRANSFER_64K (USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT) +#define UMS_DISK_MAX_IO_TRANSFER_32K (UMS_DISK_MAX_IO_TRANSFER_64K / 2) + +#define UMS_SCSI_TRANSFER_512K (0x80000 >> UMS_DISK_LBA_SHIFT) + +#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER >> UMS_DISK_LBA_SHIFT) + +// Length of a SCSI Command Data Block. +#define SCSI_MAX_CMD_SZ 16 + +// SCSI device types +#define SCSI_TYPE_DISK 0x00 + +// SCSI commands. +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_LOG_SENSE 0x4D +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1A +#define SC_MODE_SENSE_10 0x5A +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xA8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_READ_HEADER 0x44 +#define SC_READ_TOC 0x43 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1D +#define SC_START_STOP_UNIT 0x1B +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2F +#define SC_WRITE_6 0x0A +#define SC_WRITE_10 0x2A +#define SC_WRITE_12 0xAA + +// SCSI Sense Key/Additional Sense Code/ASC Qualifier values. +#define SS_NO_SENSE 0x0 +#define SS_COMMUNICATION_FAILURE 0x40800 +#define SS_INVALID_COMMAND 0x52000 +#define SS_INVALID_FIELD_IN_CDB 0x52400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x52100 +#define SS_MEDIUM_NOT_PRESENT 0x23A00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x55302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x62800 +#define SS_RESET_OCCURRED 0x62900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x53900 +#define SS_UNRECOVERED_READ_ERROR 0x31100 +#define SS_WRITE_ERROR 0x30C02 +#define SS_WRITE_PROTECTED 0x72700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + +enum ums_state { + UMS_STATE_NORMAL = 0, + UMS_STATE_ABORT_BULK_OUT, + UMS_STATE_PROTOCOL_RESET, + UMS_STATE_EXIT, + UMS_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +enum buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +typedef struct _bulk_recv_pkt_t { + u32 Signature; // 'USBC'. + u32 Tag; // Unique per command id. + u32 DataTransferLength; // Size of the data. + u8 Flags; // Direction in bit 7. + u8 Lun; // LUN (normally 0). + u8 Length; // Of the CDB, <= SCSI_MAX_CMD_SZ. + u8 CDB[16]; // Command Data Block. +} bulk_recv_pkt_t; + +typedef struct _bulk_send_pkt_t { + u32 Signature; // 'USBS'. + u32 Tag; // Same as original command. + u32 Residue; // Amount not transferred. + u8 Status; +} bulk_send_pkt_t; + +typedef struct _logical_unit_t +{ + sdmmc_t *sdmmc; + sdmmc_storage_t *storage; + + u32 num_sectors; + u32 offset; + + int unmounted; + + u32 ro; + u32 type; + u32 partition; + u32 removable; + u32 prevent_medium_removal; + + u32 info_valid; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; +} logical_unit_t; + +typedef struct _bulk_ctxt_t { + u32 bulk_in; + int bulk_in_status; + u32 bulk_in_length; + u32 bulk_in_length_actual; + u8 *bulk_in_buf; + enum buffer_state bulk_in_buf_state; + + u32 bulk_out; + int bulk_out_status; + u32 bulk_out_length; + u32 bulk_out_length_actual; + int bulk_out_ignore; + u8 *bulk_out_buf; + enum buffer_state bulk_out_buf_state; +} bulk_ctxt_t; + +typedef struct _usbd_gadget_ums_t { + bulk_ctxt_t bulk_ctxt; + + int cmnd_size; + u8 cmnd[SCSI_MAX_CMD_SZ]; + + u32 lun_idx; // lun index + logical_unit_t lun; + + u32 bulk_out_maxpacket; // 512 + enum ums_state state; // For exception handling. + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + + u32 phase_error; + u32 short_packet_received; + + int thread_wakeup_needed; + int can_stall; + + u32 timeouts; + + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usbd_gadget_ums_t; + +static inline void put_array_le_to_be16(u16 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 8; + _p[1] = val; +} + +static inline void put_array_le_to_be32(u32 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 24; + _p[1] = val >> 16; + _p[2] = val >> 8; + _p[3] = val; +} + +static inline u16 get_array_be_to_le16(const void *p) +{ + const u8 *_p = p; + u16 val = _p[0] << 8 | _p[1]; + return val; +} + +static inline u32 get_array_be_to_le24(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 16) | (_p[1] << 8) | _p[2]; + return val; +} + +static inline u32 get_array_be_to_le32(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3]; + return val; +} + +static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state) +{ + /* Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. */ + if (ums->state <= new_state) { + ums->state = new_state; + ums->thread_wakeup_needed = 1; + } +} + +static void ums_handle_ep0_ctrl(usbd_gadget_ums_t *ums) +{ + if (usbd_handle_ep0_pending_control_transfer()) + raise_exception(ums, UMS_STATE_PROTOCOL_RESET); +} + +static int ums_wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums) +{ + /* usbd_set_ep_wedge(bulk_ctxt->bulk_in); */ + + return 0; +} + +static int ums_set_stall(u32 ep) +{ + usbd_set_ep_stall(ep, 1); + + return 0; +} + +static int ums_clear_stall(u32 ep) +{ + usbd_set_ep_stall(ep, 0); + + return 0; +} + +static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_device_write_ep1_in( + bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, + &bulk_ctxt->bulk_in_length_actual, sync); + + if (bulk_ctxt->bulk_in_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(bulk_ctxt->bulk_in); + } + + if (sync) + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_device_read_ep1_out( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual, sync); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + if (sync) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_out_status = usb_device_read_ep1_out_big_reads( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; +} + +static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_device_ep1_in_writing_finish(&bulk_ctxt->bulk_in_length_actual); + + if (bulk_ctxt->bulk_in_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(bulk_ctxt->bulk_in); + } + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_device_ep1_out_reading_finish(&bulk_ctxt->bulk_out_length_actual); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _ums_reset_buffer(bulk_ctxt_t *bulk_ctxt, u32 ep) +{ + if (ep == bulk_ctxt->bulk_in) + bulk_ctxt->bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + else + bulk_ctxt->bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; +} + +/* + * The following are old data based on max 64KB SCSI transfers. + * The endpoint xfer is actually 41.2 MB/s and SD card max 39.2 MB/s, with higher SCSI + * transfers, but the concurrency still helps and increases speeds by 20%. + * + * Concurrency of the SDMMC and USB xfers is very important with no cache. + * The worst offender being the SD card. We are already limited by bus, so + * concurrency helps minimize the SDMMC overhead. + * Max achieved bulk endpoint rate on a Tegra X1 and USB2.0 is 39.4 MB/s. + * + * USB bulk endpoint raw max transfer rate: + * 39.4MB/S - SCSI 128KB. + * 38.2MB/s - SCSI 64KB. + * + * 128 KB, 64 KB, 32 KB, 16 KB, 8 KB - Internal SDMMC I\O Sizes + * ------------------------------------------------------------------------------------- + * eMMC - Toshiba - 4MB reads: 314.8 MB/s: + * 225.9 MB/s, 168.6 MB/s, 114.7 MB/s, 86.4 MB/s, 50.3 MB/s - RAW SDMMC. + * 33.5 MB/s, 31.9 MB/s, 29.3 MB/s, 27.1 MB/s, 22.1 MB/s - SCSI 128KB, No concurrency. + * 33.5 MB/s, 35.3 MB/s, 36.3 MB/s, 37.3 MB/s, 37.8 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 31.1 MB/s, 28.7 MB/s, 26.5 MB/s, 21.7 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 31.1 MB/s, 32.7 MB/s, 34.4 MB/s, 35.0 MB/s - SCSI 64KB, Concurrency. + * + * SD Card - Samsung Evo+ 128GB - 4MB reads: 91.6 MB/s: + * 72.6 MB/s, 62.8 MB/s, 47.4 MB/s, 31.1 MB/s, 18.5 MB/s - RAW SDMMC. + * 25.5 MB/s, 24.2 MB/s, 21.5 MB/s, 17.4 MB/s, 12.6 MB/s - SCSI 128KB, No concurrency. + * 25.5 MB/s, 30.0 MB/s, 32.6 MB/s, 28.3 MB/s, 18.0 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 23.8 MB/s, 21.2 MB/s, 17.1 MB/s, 12.5 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 23.8 MB/s, 27.2 MB/s, 25.8 MB/s, 17.5 MB/s - SCSI 64KB, Concurrency. + */ + +static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 lba_offset; + bool first_read = true; + u8 *sdmmc_buf = (u8 *)SDXC_BUF_ALIGNED; + + // Get the starting LBA and check that it's not too big. + if (ums->cmnd[0] == SC_READ_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits, but we don't use them. + if ((ums->cmnd[1] & ~0x18) != 0) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + // Check that request data size is not 0. + u32 amount_left = ums->data_size_from_cmnd >> UMS_DISK_LBA_SHIFT; + if (!amount_left) + return -5; // I/O error. /* No default reply */ + + // Limit IO transfers based on request for faster concurrent reads. + u32 max_io_transfer = (amount_left >= UMS_SCSI_TRANSFER_512K) ? + UMS_DISK_MAX_IO_TRANSFER_64K : UMS_DISK_MAX_IO_TRANSFER_32K; + + while (true) + { + // Max io size and end sector limits. + u32 amount = MIN(amount_left, max_io_transfer); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + + // Check if it is a read past the end sector. + if (!amount) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + bulk_ctxt->bulk_in_length = 0; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + break; + } + + // Do the SDMMC read. + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf)) + amount = 0; + + // Wait for the async USB transfer to finish. + if (!first_read) + _ums_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in); + + lba_offset += amount; + amount_left -= amount; + ums->residue -= amount << UMS_DISK_LBA_SHIFT; + + bulk_ctxt->bulk_in_length = amount << UMS_DISK_LBA_SHIFT; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + bulk_ctxt->bulk_in_buf = sdmmc_buf; + + // If an error occurred, report it and its position. + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Read"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + // Last SDMMC read. Last part will be sent by the finish reply function. + if (!amount_left) + break; + + // Start the USB transfer. + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, false); + first_read = false; + + // Increment our buffer to read new data. + sdmmc_buf += amount << UMS_DISK_LBA_SHIFT; + } + + return -5; // I/O error no default reply here. /* No default reply */ +} + +/* + * Writes are another story. + * Tests showed that big writes are faster than concurrent 32K usb reads + writes. + * The only thing that can help here is caching the writes. But for the simplicity + * of this implementation it will not be implemented yet. + */ + +static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + static char txt_buf[256]; + u32 amount_left_to_req, amount_left_to_write; + u32 usb_lba_offset, lba_offset; + u32 amount; + + if (ums->lun.ro) + { + ums->lun.sense_data = SS_WRITE_PROTECTED; + + return -22; // Invalid argument. + } + + if (ums->cmnd[0] == SC_WRITE_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits. We only implement FUA by performing synchronous output. + if (ums->cmnd[1] & ~0x18) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + + // Check that starting LBA is not past the end sector offset. + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + /* Carry out the file writes */ + usb_lba_offset = lba_offset; + amount_left_to_req = ums->data_size_from_cmnd; + amount_left_to_write = ums->data_size_from_cmnd; + + while (amount_left_to_write > 0) + { + + /* Queue a request for more data from the host */ + if (amount_left_to_req) + { + + // Limit write to max supported read from EP OUT. + amount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER << UMS_DISK_LBA_SHIFT); + + if (usb_lba_offset >= ums->lun.num_sectors) //////////Check if it works with concurrency + { + ums->set_text(ums->label, "#C7EA46 Status:# Write Error - Past last sector"); + amount_left_to_req = 0; + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = usb_lba_offset; + ums->lun.info_valid = 1; + continue; + } + + // Get the next buffer. + usb_lba_offset += amount >> UMS_DISK_LBA_SHIFT; + ums->usb_amount_left -= amount; + amount_left_to_req -= amount; + + bulk_ctxt->bulk_out_length = amount; + + _ums_transfer_out_big_read(ums, bulk_ctxt); + } + + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + { + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // Did something go wrong with the transfer?. + if (bulk_ctxt->bulk_out_status != 0) + { + ums->lun.sense_data = SS_COMMUNICATION_FAILURE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + sprintf(txt_buf, "#C7EA46 Status:# Write Error - Comm failure %d", bulk_ctxt->bulk_out_status); + ums->set_text(ums->label, txt_buf); + break; + } + + amount = bulk_ctxt->bulk_out_length_actual; + + if ((ums->lun.num_sectors - lba_offset) < (amount >> UMS_DISK_LBA_SHIFT)) + { + DPRINTF("write %X @ %X beyond end %X\n", amount, lba_offset, ums->lun.num_sectors); + amount = (ums->lun.num_sectors - lba_offset) << UMS_DISK_LBA_SHIFT; + } + + /* + * Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = MIN(amount, bulk_ctxt->bulk_out_length); + + /* Don't write a partial block */ + amount -= (amount & 511); + if (amount == 0) + goto empty_write; + + /* Perform the write */ + if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset, + amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf)) + amount = 0; + +DPRINTF("file write %X @ %X\n", amount, lba_offset); + + lba_offset += amount >> UMS_DISK_LBA_SHIFT; + amount_left_to_write -= amount; + ums->residue -= amount; + + /* If an error occurred, report it and its position */ + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Write"); + ums->lun.sense_data = SS_WRITE_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + empty_write: + // Did the host decide to stop early? + if (bulk_ctxt->bulk_out_length_actual < bulk_ctxt->bulk_out_length) + { + ums->set_text(ums->label, "#C7EA46 Status:# Empty Write"); + ums->short_packet_received = 1; + break; + } + } + } + + return -5; // I/O error. /* No default reply */ +} + +static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + // Check that start LBA is past the end sector offset. + u32 lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + // We allow DPO but we don't implement it. Check that nothing else is enabled. + if (ums->cmnd[1] & ~0x10) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + u32 verification_length = get_array_be_to_le16(&ums->cmnd[7]); + if (verification_length == 0) + return -5; // I/O error. /* No default reply */ + + u32 amount; + while (verification_length > 0) + { + + // Limit to EP buffer size and end sector offset. + amount = MIN(verification_length, USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + if (amount == 0) { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)) + amount = 0; + +DPRINTF("File read %X @ %X\n", amount, lba_offset); + + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error file verify"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + lba_offset += amount; + verification_length -= amount; + } + return 0; +} + +static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + memset(buf, 0, 36); + + // Enable Vital Product Data (EVPD) and Unit Serial Number. + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) + { + buf[0] = 0; + buf[1] = ums->cmnd[2]; + buf[2] = 0; + buf[3] = 20; // Additional length. + + buf += 4; + sprintf((char *)buf, "%04X%s", + ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC "); + + switch (ums->lun.partition) + { + case 0: + strcpy((char *)buf + strlen((char *)buf), "RAW"); + break; + case EMMC_GPP + 1: + sprintf((char *)buf + strlen((char *)buf), "GPP"); + break; + case EMMC_BOOT0 + 1: + sprintf((char *)buf + strlen((char *)buf), "BOOT0"); + break; + case EMMC_BOOT1 + 1: + sprintf((char *)buf + strlen((char *)buf), "BOOT1"); + break; + } + + for (u32 i = strlen((char *)buf); i < 20; i++) + buf[i] = ' '; + + return 24; + } + else /* if (ums->cmnd[1] == 0 && ums->cmnd[2] == 0) */ // Standard inquiry. + { + buf[0] = SCSI_TYPE_DISK; + buf[1] = ums->lun.removable ? 0x80 : 0; + buf[2] = 6; // ANSI INCITS 351-2001 (SPC-2).////////SPC2: 4, SPC4: 6 + buf[3] = 2; // SCSI-2 INQUIRY data format. + buf[4] = 31; // Additional length. + // buf5-7: No special options. + + // Vendor ID. Max 8 chars. + buf += 8; + strcpy((char *)buf, "hekate"); + + // Product ID. Max 16 chars. + buf += 8; + switch (ums->lun.partition) + { + case 0: + sprintf((char *)buf, "%s", "SD RAW"); + break; + case EMMC_GPP + 1: + sprintf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP"); + break; + case EMMC_BOOT0 + 1: + sprintf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0"); + break; + case EMMC_BOOT1 + 1: + sprintf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1"); + break; + } + + // Rev ID. Max 4 chars. + buf += 16; + strcpy((char *)buf, "1.00"); + + return 36; + } +} + +static int _scsi_request_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 sd, sdinfo; + int valid; + + sd = ums->lun.sense_data; + sdinfo = ums->lun.sense_data_info; + valid = ums->lun.info_valid << 7; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + + memset(buf, 0, 18); + buf[0] = valid | 0x70; // Valid, current error. + buf[2] = SK(sd); + put_array_le_to_be32(sdinfo, &buf[3]); // Sense information. + buf[7] = 18 - 8; // Additional sense length. + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + + return 18; +} + +static int _scsi_read_capacity(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 lba = get_array_be_to_le32(&ums->cmnd[2]); + int pmi = ums->cmnd[8]; + + // Check the PMI and LBA fields. + if (pmi > 1 || (pmi == 0 && lba != 0)) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + put_array_le_to_be32(ums->lun.num_sectors - 1, &buf[0]); // Max logical block. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + + return 8; +} + +static int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + u8 sub_page_code = ums->cmnd[3]; + + if (ums->cmnd[1] & 1) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return -22; // Invalid argument. + } + + if (pc != 1) // Current cumulative values. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + memset(buf, 0, 8); + if (page_code == 0x00 && !sub_page_code) // Supported pages. + { + valid_page = true; + buf[0] = 0x00; // Page code. + buf += 4; + + buf[0] = 0x00; // Page 0. + buf[1] = 0x0D; // Page 1. + + buf += 2; + } + else if (page_code == 0x0d && !sub_page_code) // Temperature. + { + valid_page = true; + buf[0] = 0x0D; + buf += 4; + + put_array_le_to_be16(0, &buf[0]); // Param code. + buf[2] = 1; // Param control byte. + buf[3] = 2; // Param length. + buf[4] = 0; // Reserved. + buf[5] = 35; // Temperature (C) current (PCB here). + + put_array_le_to_be16(0, &buf[6]); // PARAMETER CODE + buf[8] = 1; // Param control byte. + buf[9] = 2; // Param length. + buf[10] = 0; // Reserved. + buf[11] = 60; // Temperature (C) reference. + + buf += 12; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + put_array_le_to_be16(len - 4, &buf0[2]); + + return len; +} + +static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + bool changeable_values = pc == 1; + bool all_pages = page_code == 0x3F; + + if ((ums->cmnd[1] & ~0x08) != 0) // Mask away DBD. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + if (pc == 3) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return -22; // Invalid argument. + } + + /* Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. */ + memset(buf, 0, 8); + if (ums->cmnd[0] == SC_MODE_SENSE_6) + { + buf[2] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 4; + } + else // SC_MODE_SENSE_10. + { + buf[3] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 8; + } + + // The only page we support is the Caching page. + // What about x1C + if (page_code == 0x08 || all_pages) + { + valid_page = true; + buf[0] = 0x08; // Page code. + buf[1] = 18; // Page length. + memset(buf + 2, 0, 18); // Set all parameters to 0. + + // None of the fields are changeable. + if (!changeable_values) + { + // Write Cache enable, Read Cache not disabled, Multiplication Factor off. + buf[2] = 0x04; + + // Multiplication Factor is disabled, so all values below are 1x LBA. + put_array_le_to_be16(0xFFFF, &buf[4]); // Disable Prefetch if >32MB. + put_array_le_to_be16(0x0000, &buf[6]); // Minimum Prefetch 0MB. + put_array_le_to_be16(0xFFFF, &buf[8]); // Maximum Prefetch 32MB. + put_array_le_to_be16(0xFFFF, &buf[10]); // Maximum Prefetch ceiling 32MB. + } + + buf += 20; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + /* Store the mode data length */ + if (ums->cmnd[0] == SC_MODE_SENSE_6) + buf0[0] = len - 1; + else + put_array_le_to_be16(len - 2, buf0); + + return len; +} + +static int _scsi_start_stop(usbd_gadget_ums_t *ums) +{ + int loej, start; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return -22; // Invalid argument. + } + else if ((ums->cmnd[1] & ~0x01) != 0 || // Mask away Immed. + (ums->cmnd[4] & ~0x03) != 0) // Mask LoEj, Start. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; + } + + loej = ums->cmnd[4] & 0x02; + start = ums->cmnd[4] & 0x01; + + // We do not support re-mounting. + if (start) + { + if (ums->lun.unmounted) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return -22; + } + + return 0; + } + + // Check if we are allowed to unload the media. + if (ums->lun.prevent_medium_removal) + { + ums->set_text(ums->label, "#C7EA46 Status:# Unload attempt prevented"); + ums->lun.sense_data = SS_MEDIUM_REMOVAL_PREVENTED; + + return -22; + } + + if (!loej) + return 0; + + // Unmount means we exit UMS because of ejection. + ums->lun.unmounted = 1; + + return 0; +} + +static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) +{ + int prevent; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return -22; // Invalid argument. + } + + prevent = ums->cmnd[4] & 0x01; + if ((ums->cmnd[4] & ~0x01) != 0) // Mask away Prevent. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + // Notify for possible unmounting? + // Normally we sync here but we do synced writes to SDMMC. + if (ums->lun.prevent_medium_removal && !prevent) + ; + + ums->lun.prevent_medium_removal = prevent; + + return 0; +} + +static int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor. + buf += 4; + + put_array_le_to_be32(ums->lun.num_sectors, &buf[0]); // Number of blocks. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + buf[4] = 0x02; // Current capacity. + + return 12; +} + +// Check whether the command is properly formed and whether its data size +// and direction agree with the values we already have. +static int _ums_check_scsi_cmd(usbd_gadget_ums_t *ums, int cmnd_size, + enum data_direction data_dir, u32 mask, int needs_medium) +{ +//const char dirletter[4] = {'u', 'o', 'i', 'n'}; +DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", + ums->cmnd[0], cmnd_size, dirletter[(int)ums->data_dir], + ums->data_size_from_cmnd, ums->cmnd_size, + dirletter[(int)data_dir], ums->data_size); + + // We can't reply if we don't know the direction and size. + if (ums->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + + // This is a phase error but we continue and only transfer as much we can. + if (ums->data_size < ums->data_size_from_cmnd) + { + ums->data_size_from_cmnd = ums->data_size; + ums->phase_error = 1; + } + + ums->residue = ums->data_size; + ums->usb_amount_left = ums->data_size; + + if (ums->data_dir != data_dir && ums->data_size_from_cmnd > 0) + { + ums->phase_error = 1; + + return -22; // Invalid argument. + } + + // Cmd length verification. + if (cmnd_size != ums->cmnd_size) + { + + // Special case workaround for Windows and Xbox 360. + if (cmnd_size <= ums->cmnd_size) + cmnd_size = ums->cmnd_size; + else + { + ums->phase_error = 1; + + return -22; // Invalid argument. + } + } + + // check that LUN ums->cmnd[1] >> 5 is 0 because of only one. + + if (ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + // If a unit attention condition exists, only INQUIRY and REQUEST SENSE + // commands are allowed. + if (ums->lun.unit_attention_data != SS_NO_SENSE && ums->cmnd[0] != SC_INQUIRY && + ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = ums->lun.unit_attention_data; + ums->lun.unit_attention_data = SS_NO_SENSE; + + return -22; + } + + // Check that only command bytes listed in the mask are set. + ums->cmnd[1] &= 0x1F; // Mask away the LUN. + for (u32 i = 1; i < cmnd_size; ++i) + { + if (ums->cmnd[i] && !(mask & (1 << i))) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + + // If the medium isn't mounted and the command needs to access it, return an error. + if (ums->lun.unmounted && needs_medium) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return -22; + } + + return 0; +} + +static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 len; + int reply = -22; // Invalid argument. + + ums->phase_error = 0; + ums->short_packet_received = 0; + + switch (ums->cmnd[0]) + { + case SC_INQUIRY: + ums->data_size_from_cmnd = ums->cmnd[4]; + u32 mask = (1<<4); + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) // Inquiry S/N. + mask = (1<<1) | (1<<2) | (1<<4); + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, mask, 0); + if (reply == 0) + reply = _scsi_inquiry(ums, bulk_ctxt); + break; + + case SC_LOG_SENSE: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_log_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SELECT_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (1<<1) | (1<<4), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; + } + break; + + case SC_MODE_SELECT_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (3<<7), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; + } + break; + + case SC_MODE_SENSE_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (1<<4), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SENSE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<4), 0); + if (reply == 0) + reply = _scsi_prevent_allow_removal(ums); + break; + + case SC_READ_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_CAPACITY: + ums->data_size_from_cmnd = 8; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (0xf<<2) | (1<<8), 1); + if (reply == 0) + reply = _scsi_read_capacity(ums, bulk_ctxt); + break; + case SC_READ_FORMAT_CAPACITIES: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (3<<7), 1); + if (reply == 0) + reply = _scsi_read_format_capacities(ums, bulk_ctxt); + break; + + case SC_REQUEST_SENSE: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<4), 0); + if (reply == 0) + reply = _scsi_request_sense(ums, bulk_ctxt); + break; + + case SC_START_STOP_UNIT: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<1) | (1<<4), 0); + if (reply == 0) + reply = _scsi_start_stop(ums); + break; + + case SC_SYNCHRONIZE_CACHE: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_NONE, (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = 0; // Don't bother + break; + + case SC_TEST_UNIT_READY: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, 0, 1); + break; + + // This command is used by Windows. We support a minimal version and BytChk must be 0. + case SC_VERIFY: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_NONE, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_verify(ums, bulk_ctxt); + break; + + case SC_WRITE_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + // Mandatory commands that we don't implement. No need. + case SC_READ_HEADER: + case SC_READ_TOC: + case SC_FORMAT_UNIT: + case SC_RELEASE: + case SC_RESERVE: + case SC_SEND_DIAGNOSTIC: + default: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, ums->cmnd_size, DATA_DIR_UNKNOWN, 0xFF, 0); + if (reply == 0) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; // Invalid argument. + } + break; + } + + if (reply == -22) // Invalid argument. + reply = 0; // Error reply length. + + // Set up reply buffer for finish_reply(). Otherwise it's already set. + if (reply >= 0 && ums->data_dir == DATA_DIR_TO_HOST) + { + reply = MIN((u32)reply, ums->data_size_from_cmnd); + bulk_ctxt->bulk_in_length = reply; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + ums->residue -= reply; + } + + return 0; +} + +static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; // For the first iteration. + u32 current_len_to_keep = bulk_ctxt->bulk_in_length; + ums->usb_amount_left = current_len_to_keep + ums->residue; + + while (ums->usb_amount_left > 0) + { + u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); + bulk_ctxt->bulk_in_length = nsend; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + ums->usb_amount_left -= nsend; + current_len_to_keep = 0; + } + + return 0; +} + +static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + if (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY || ums->usb_amount_left > 0) + { + // Try to submit another request if we need one. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_EMPTY && ums->usb_amount_left > 0) + { + u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + + bulk_ctxt->bulk_out_length = amount; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + ums->usb_amount_left -= amount; + + return 0; + } + + // Throw away the data in a filled buffer. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // A short packet or an error ends everything. + if (bulk_ctxt->bulk_out_length_actual != bulk_ctxt->bulk_out_length || + bulk_ctxt->bulk_out_status != 0) + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + return -4; // Interrupted system call + } + } + return 0; +} + +static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = 0; + + switch (ums->data_dir) { + case DATA_DIR_NONE: + break; // Nothing to send. + + // If this is a CB or CBI with an unknown command, we mustn't + // try to send or receive any data. Stall if we can and wait reset. + case DATA_DIR_UNKNOWN: + if (ums->can_stall) + { + ums_set_stall(bulk_ctxt->bulk_out); + rc = ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# Direction unknown. Stalled both EP"); + } // Else do nothing. + break; + + // All but the last buffer of data have already been sent. + case DATA_DIR_TO_HOST: + if (ums->data_size) + { + // If there's no residue, simply send the last buffer. + if (!ums->residue) + { + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't + * stall, pad out the remaining data with 0's. */ + } + else if (ums->can_stall) + { + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + rc = ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# Residue. Stalled EP IN"); + } + else + rc = pad_with_zeros(ums, bulk_ctxt); + } + + // In case we used SDMMC transfer, reset the buffer address. + _ums_reset_buffer(bulk_ctxt, bulk_ctxt->bulk_in); + break; + + // We have processed all we want from the data the host has sent. + // There may still be outstanding bulk-out requests. + case DATA_DIR_FROM_HOST: + if (ums->residue) + { + if (ums->short_packet_received) // Did the host stop sending unexpectedly early? + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + rc = -4; // Interrupted system call + } + else // We can't stall. Read in the excess data and throw it away. + rc = throw_away_data(ums, bulk_ctxt); + } + + break; + } + + return rc; +} + +/* + * Medium ejection heuristics. + * + * Windows: + * Uses Start/Stop Unit. Only Stop with LoEj. Observed ONLY on very specific windows machines. + * Uses Prevent/Allow Medium Removal. (For big reads and ANY write.) //////Except trivial writes. Needs check with prefetch ON + * Sends Test Unit Ready every 1s at idle. (Needs 1 EP Timeout protection: 2s) + * Does not send data when ejects. In the case it does, + * it loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0 and only goes in J-State when it ejects. + * + * Linux: + * Uses Start/Stop Unit. Stops with LoEj when Media prevention is off. + * Uses Prevent/Allow Medium Removal. (For big read and any write.) + * Sends Test Unit Ready every 2s at idle. (Needs 2 EP Timeouts protection: 4s) + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + * + * Mac OS: + * Uses Start/Stop. Stops with LoEj when Allow Medium Removal is enabled. + * Uses Prevent/Allow Medium Removal. (Properly. Enables at mount and only disables it when ejects.) + * Does not send Test Unit Ready at idle. But Prevent Medium Removal is enabled. + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + */ + +static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + /* Was this a real packet? Should it be ignored? */ + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore || ums->lun.unmounted) + { + if (bulk_ctxt->bulk_out_status || ums->lun.unmounted) + { + DPRINTF("USB: EP timeout\n"); + // In case we disconnected, exit UMS. + // Raise timeout if removable and didn't got a unit ready command inside 4s. + if (bulk_ctxt->bulk_out_status == 28 || + (bulk_ctxt->bulk_out_status == 3 && ums->lun.removable && !ums->lun.prevent_medium_removal)) + { + if (bulk_ctxt->bulk_out_status == 3) + { + if (usb_device_get_port_status() == 0x885) + { + ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep"); + ums->timeouts += 10; + } + else + DPRINTF("USB: EP removable\n"); + } + else + { + gfx_printf("USB: EP disabled\n"); + msleep(500); + } + + ums->timeouts += 4; + } + + if (ums->lun.unmounted) + { + ums->set_text(ums->label, "#C7EA46 Status:# Medium unmounted"); + ums->timeouts++; + } + + if (ums->timeouts > 20) + raise_exception(ums, UMS_STATE_EXIT); + } + + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore) + return -22; // Invalid argument. + } + + /* Is the CBW valid? */ + bulk_recv_pkt_t *cbw = (bulk_recv_pkt_t *)bulk_ctxt->bulk_out_buf; + if (bulk_ctxt->bulk_out_length_actual != USB_BULK_CB_WRAP_LEN || cbw->Signature != USB_BULK_CB_SIG) + { + gfx_printf("USB: invalid CBW: len %X sig 0x%X\n", bulk_ctxt->bulk_out_length_actual, cbw->Signature); + + // The Bulk-only spec says we MUST stall the IN endpoint + // (6.6.1), so it's unavoidable. It also says we must + // retain this state until the next reset, but there's + // no way to tell the controller driver it should ignore + // Clear-Feature(HALT) requests. + // + // We aren't required to halt the OUT endpoint; instead + // we can simply accept and discard any data received + // until the next reset. + ums_wedge_bulk_in_endpoint(ums); + bulk_ctxt->bulk_out_ignore = 1; + return -22; // Invalid argument. + } + + /* Is the CBW meaningful? */ + if (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length <= 0 || cbw->Length > SCSI_MAX_CMD_SZ) + { + gfx_printf("USB: non-meaningful CBW: lun = %X, flags = 0x%X, cmdlen %X\n", + cbw->Lun, cbw->Flags, cbw->Length); + + /* We can do anything we want here, so let's stall the + * bulk pipes if we are allowed to. */ + if (ums->can_stall) + { + ums_set_stall(bulk_ctxt->bulk_out); + ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# CBW unknown - Stalled both EP"); + } + + return -22; // Invalid argument. + } + + /* Save the command for later */ + ums->cmnd_size = cbw->Length; + memcpy(ums->cmnd, cbw->CDB, ums->cmnd_size); + + if (cbw->Flags & USB_BULK_IN_FLAG) + ums->data_dir = DATA_DIR_TO_HOST; + else + ums->data_dir = DATA_DIR_FROM_HOST; + + ums->data_size = cbw->DataTransferLength; + + if (ums->data_size == 0) + ums->data_dir = DATA_DIR_NONE; + + ums->lun_idx = cbw->Lun; + ums->tag = cbw->Tag; + + if (!ums->lun.unmounted) + ums->timeouts = 0; + + return 0; +} + +static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = 0; + + /* Wait for the next buffer to become available */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY) + // { + // //wait irq. + // } + + bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; + + /* Queue a request to read a Bulk-only CBW */ + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + + /* We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. */ + + /* Wait for the CBW to arrive */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_FULL) + // { + // //wait irq. + // } + + rc = received_cbw(ums, bulk_ctxt); + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + return rc; +} + +static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 status = USB_STATUS_PASS; + u32 sd = ums->lun.sense_data; + + if (ums->phase_error) + { + ums->set_text(ums->label, "#C7EA46 Status:# Phase-error"); + status = USB_STATUS_PHASE_ERROR; + sd = SS_INVALID_COMMAND; + } + else if (sd != SS_NO_SENSE) + { + DPRINTF("USB: CMD fail\n"); + status = USB_STATUS_FAIL; + DPRINTF("USB: Sense: SK x%02X, ASC x%02X, ASCQ x%02X; info x%X\n", + SK(sd), ASC(sd), ASCQ(sd), ums->lun.sense_data_info); + } + + /* Store and send the Bulk-only CSW */ + bulk_send_pkt_t *csw = (bulk_send_pkt_t *)bulk_ctxt->bulk_in_buf; + + csw->Signature = USB_BULK_CS_SIG; + csw->Tag = ums->tag; + csw->Residue = ums->residue; + csw->Status = status; + + bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); +} + +static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + enum ums_state old_state; + + /* Clear out the controller's fifos */ + usbd_flush_endpoint(bulk_ctxt->bulk_in); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + old_state = ums->state; + + if (old_state != UMS_STATE_ABORT_BULK_OUT) + { + ums->lun.prevent_medium_removal = 0; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.unit_attention_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + ums->state = UMS_STATE_NORMAL; + + /* Carry out any extra actions required for the exception */ + switch (old_state) + { + case UMS_STATE_NORMAL: + break; + case UMS_STATE_ABORT_BULK_OUT: + send_status(ums, bulk_ctxt); + break; + + case UMS_STATE_PROTOCOL_RESET: + /* In case we were forced against our will to halt a + * bulk endpoint, clear the halt now. (The SuperH UDC + * requires this.) */ + if (bulk_ctxt->bulk_out_ignore) + { + bulk_ctxt->bulk_out_ignore = 0; + ums_clear_stall(bulk_ctxt->bulk_in); + } + ums->lun.unit_attention_data = SS_RESET_OCCURRED; + break; + + case UMS_STATE_EXIT: + ums->state = UMS_STATE_TERMINATED; /* Stop the thread */ + break; + + default: + break; + } +} + +static inline void _system_maintainance(usbd_gadget_ums_t *ums) +{ + static u32 timer_dram = 0; + static u32 timer_status_bar = 0; + + u32 time = get_tmr_ms(); + + if (timer_dram < time) + { + minerva_periodic_training(); + timer_dram = get_tmr_ms() + 100; + } + else if (timer_status_bar < time) + { + ums->system_maintenance(true); + timer_status_bar = get_tmr_ms() + 30000; + } +} + +int usb_device_gadget_ums(usb_ctxt_t *usbs) +{ + int res = 0; + sdmmc_t sdmmc; + sdmmc_storage_t storage; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_device_init()) + { + usbd_end(false, true); + return 1; + } + + usbd_gadget_ums_t ums; + memset(&ums, 0, sizeof(usbd_gadget_ums_t)); + + ums.bulk_out_maxpacket = usbd_get_max_pkt_length(USB_EP_BULK_IN); + ums.state = UMS_STATE_NORMAL; + ums.can_stall = 0; + + ums.bulk_ctxt.bulk_in = 3; + ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + + ums.bulk_ctxt.bulk_out = 2; + ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; + + // Set LUN parameters. + ums.lun.ro = usbs->ro; + ums.lun.type = usbs->type; + ums.lun.partition = usbs->partition; + ums.lun.offset = usbs->offset; + ums.lun.removable = 1; // Always removable to force OSes to use prevent media removal. + ums.lun.unit_attention_data = SS_RESET_OCCURRED; + + // Set system functions + ums.label = usbs->label; + ums.set_text = usbs->set_text; + ums.system_maintenance = usbs->system_maintenance; + + ums.set_text(ums.label, "#C7EA46 Status:# Mounting disk"); + + // Initialize sdmmc. + if (usbs->type == MMC_SD) + { + sd_mount(); + sd_unmount(); + ums.lun.sdmmc = &sd_sdmmc; + ums.lun.storage = &sd_storage; + } + else + { + ums.lun.sdmmc = &sdmmc; + ums.lun.storage = &storage; + sdmmc_storage_init_mmc(ums.lun.storage, ums.lun.sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); + sdmmc_storage_set_mmc_partition(ums.lun.storage, ums.lun.partition - 1); + } + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_device_ep0_initialize(USB_GADGET_UMS)) + goto error; + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN"); + + if (usb_device_get_max_lun(0)) // One device for now. + goto error; + + ums.set_text(ums.label, "#C7EA46 Status:# Started UMS"); + + if (usbs->sectors) + ums.lun.num_sectors = usbs->sectors; + else + ums.lun.num_sectors = ums.lun.storage->sec_cnt; + + do + { + // Do DRAM training and update system tasks. + _system_maintainance(&ums); + + // Check for force unmount button combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + // Check if we are allowed to unload the media. + if (ums.lun.prevent_medium_removal) + ums.set_text(ums.label, "#C7EA46 Status:# Unload attempt prevented"); + else + break; + } + + if (ums.state != UMS_STATE_NORMAL) + { + handle_exception(&ums, &ums.bulk_ctxt); + continue; + } + + ums_handle_ep0_ctrl(&ums); + + if (get_next_command(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + ums_handle_ep0_ctrl(&ums); + + if (_ums_parse_scsi_cmd(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + ums_handle_ep0_ctrl(&ums); + + if (finish_reply(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + send_status(&ums, &ums.bulk_ctxt); + } while (ums.state != UMS_STATE_TERMINATED); + + ums.set_text(ums.label, "#C7EA46 Status:# Disk ejected"); + goto exit; + +error: + ums.set_text(ums.label, "#C7EA46 Status:# Timed out or canceled"); + res = 1; + +exit: + if (ums.lun.type == MMC_EMMC) + sdmmc_storage_end(ums.lun.storage); + + usbd_end(true, false); + + return res; +} diff --git a/bdk/usb/usb_t210.h b/bdk/usb/usb_t210.h new file mode 100644 index 0000000..d670317 --- /dev/null +++ b/bdk/usb/usb_t210.h @@ -0,0 +1,172 @@ +/* + * USB 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 . + */ + +#ifndef _USB_T210_H_ +#define _USB_T210_H_ + +#include + +/* General USB registers */ +#define USB1_IF_USB_SUSP_CTRL 0x400 +#define SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV (1 << 3) +#define SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV (1 << 4) +#define SUSP_CTRL_USB_PHY_CLK_VALID (1 << 7) +#define SUSP_CTRL_UTMIP_RESET (1 << 11) +#define SUSP_CTRL_UTMIP_PHY_ENB (1 << 12) +#define SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET (1 << 25) +#define USB1_IF_USB_PHY_VBUS_SENSORS 0x404 +#define USB1_UTMIP_XCVR_CFG0 0x808 +#define USB1_UTMIP_BIAS_CFG0 0x80C +#define USB1_UTMIP_HSRX_CFG0 0x810 +#define USB1_UTMIP_HSRX_CFG1 0x814 +#define USB1_UTMIP_TX_CFG0 0x820 +#define USB1_UTMIP_MISC_CFG1 0x828 +#define USB1_UTMIP_DEBOUNCE_CFG0 0x82C +#define USB1_UTMIP_SPARE_CFG0 0x834 +#define USB1_UTMIP_XCVR_CFG1 0x838 +#define USB1_UTMIP_BIAS_CFG1 0x83C +#define USB1_UTMIP_BIAS_CFG2 0x850 +#define USB1_UTMIP_XCVR_CFG2 0x854 +#define USB1_UTMIP_XCVR_CFG3 0x858 + +/* USB Queue Head Descriptor */ +#define USB2_QH_USB2D_QH_EP_BASE (USB_BASE + 0x1000) +#define USB_QHD_EP_CAP_IOS_ENABLE (1 << 15) +#define USB_QHD_EP_CAP_MAX_PKT_LEN_MASK 0x7FF +#define USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS (1 << 29) +#define USB_QHD_EP_CAP_MULTI_NON_ISO (0 << 30) +#define USB_QHD_EP_CAP_MULTI_1 (1 << 30) +#define USB_QHD_EP_CAP_MULTI_2 (2 << 30) +#define USB_QHD_EP_CAP_MULTI_3 (3 << 30) + +#define USB_QHD_TOKEN_XFER_ERROR (1 << 3) +#define USB_QHD_TOKEN_BUFFER_ERROR (1 << 5) +#define USB_QHD_TOKEN_HALTED (1 << 6) +#define USB_QHD_TOKEN_ACTIVE (1 << 7) +#define USB_QHD_TOKEN_MULT_OVERR_MASK (2 << 10) +#define USB_QHD_TOKEN_IRQ_ON_COMPLETE (1 << 15) +#define USB_QHD_TOKEN_TOTAL_BYTES_SHIFT 16 + +/* USB_OTG/USB_1 controllers register bits */ +#define USB2D_PORTSC1_SUSP (1 << 7) + +#define USB2D_USBCMD_RUN (1 << 0) +#define USB2D_USBCMD_RESET (1 << 1) +#define USB2D_USBCMD_ITC_MASK (0xFF << 16) + +#define USB2D_USBSTS_UI (1 << 0) +#define USB2D_USBSTS_UEI (1 << 1) +#define USB2D_USBSTS_PCI (1 << 2) +#define USB2D_USBSTS_FRI (1 << 3) +#define USB2D_USBSTS_SEI (1 << 4) +#define USB2D_USBSTS_AAI (1 << 5) +#define USB2D_USBSTS_URI (1 << 6) +#define USB2D_USBSTS_SRI (1 << 7) +#define USB2D_USBSTS_SLI (1 << 8) + +#define USB2D_USBMODE_CM_MASK (3 << 0) +#define USB2D_USBMODE_CM_IDLE 0 +#define USB2D_USBMODE_CM_RSVD 1 +#define USB2D_USBMODE_CM_DEVICE 2 +#define USB2D_USBMODE_CM_HOST 3 + +#define USB2D_ENDPT_STATUS_RX_OFFSET (1 << 0) +#define USB2D_ENDPT_STATUS_TX_OFFSET (1 << 16) + +#define USB2D_ENDPTCTRL_RX_EP_STALL (1 << 0) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL (0 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_ISO (1 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_BULK (2 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_INTR (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_MASK (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_INHIBIT (1 << 5) +#define USB2D_ENDPTCTRL_RX_EP_RESET (1 << 6) +#define USB2D_ENDPTCTRL_RX_EP_ENABLE (1 << 7) +#define USB2D_ENDPTCTRL_TX_EP_STALL (1 << 16) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL (0 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_ISO (1 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_BULK (2 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_INTR (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_MASK (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_INHIBIT (1 << 21) +#define USB2D_ENDPTCTRL_TX_EP_RESET (1 << 22) +#define USB2D_ENDPTCTRL_TX_EP_ENABLE (1 << 23) + +#define USB2D_HOSTPC1_DEVLC_ASUS (1 << 17) +#define USB2D_HOSTPC1_DEVLC_PHCD (1 << 22) +#define USB2D_HOSTPC1_DEVLC_PSPD_MASK (3 << 25) + +#define USB2D_OTGSC_USB_ID_PULLUP (1 << 5) +#define USB2D_OTGSC_USB_IRQ_STS_MASK (0x7F << 16) + +/* USB_OTG/USB_1 controllers registers */ +typedef struct _t210_usb2d_t +{ + vu32 id; + vu32 unk0; + vu32 hw_host; + vu32 hw_device; + vu32 hw_txbuf; + vu32 hw_rxbuf; + vu32 unk1[26]; + vu32 gptimer0ld; + vu32 gptimer0ctrl; + vu32 gptimer1ld; + vu32 gptimer1ctrl; + vu32 unk2[28]; + vu16 caplength; + vu16 hciversion; + vu32 hcsparams; + vu32 hccparams; + vu32 unk3[5]; + vu32 dciversion; + vu32 dccparams; + vu32 extsts; + vu32 usbextintr; + vu32 usbcmd; + vu32 usbsts; + vu32 usbintr; + vu32 frindex; + vu32 unk4; + vu32 periodiclistbase; + vu32 asynclistaddr; + vu32 asyncttsts; + vu32 burstsize; + vu32 txfilltuning; + vu32 unk6; + vu32 icusb_ctrl; + vu32 ulpi_viewport; + vu32 rsvd0[4]; + vu32 portsc1; + vu32 rsvd1[15]; + vu32 hostpc1_devlc; + vu32 rsvd2[15]; + vu32 otgsc; + vu32 usbmode; + vu32 unk10; + vu32 endptnak; + vu32 endptnak_enable; + vu32 endptsetupstat; + vu32 endptprime; + vu32 endptflush; + vu32 endptstatus; + vu32 endptcomplete; + vu32 endptctrl[16]; +} t210_usb2d_t; + +#endif diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c new file mode 100644 index 0000000..712629a --- /dev/null +++ b/bdk/usb/usbd.c @@ -0,0 +1,1667 @@ +/* + * USB Device 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 . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef enum +{ + USB_HW_EP0 = 0, + USB_HW_EP1 = 1 +} usb_hw_ep_t; + +typedef enum +{ + USB_EP_ADDR_CTRL_OUT = 0x00, + USB_EP_ADDR_CTRL_IN = 0x80, + USB_EP_ADDR_BULK_OUT = 0x01, + USB_EP_ADDR_BULK_IN = 0x81, +} usb_ep_addr_t; + +typedef enum +{ + USB_EP_CFG_RESET = 0, + USB_EP_CFG_STALL = 1 +} usb_ep_cfg_t; + +typedef enum +{ + USB_EP_STATUS_IDLE = 0, + USB_EP_STATUS_ACTIVE = 1, + USB_EP_STATUS_ERROR = 2, + USB_EP_STATUS_NO_CONFIG = 3, + USB_EP_STATUS_STALLED = 4, + USB_EP_STATUS_DISABLED = 5 +} usb_ep_status_t; + +typedef enum { + USB_SETUP_RECIPIENT_DEVICE = 0, + USB_SETUP_RECIPIENT_INTERFACE = 1, + USB_SETUP_RECIPIENT_ENDPOINT = 2, + USB_SETUP_RECIPIENT_OTHER = 3, + + USB_SETUP_TYPE_STANDARD = 0x00, + USB_SETUP_TYPE_CLASS = 0x20, + USB_SETUP_TYPE_VENDOR = 0x40, + USB_SETUP_TYPE_RESERVED = 0x60, + + USB_SETUP_HOST_TO_DEVICE = 0x00, + USB_SETUP_DEVICE_TO_HOST = 0x80, +} usb_setup_req_type_t; + +typedef enum { + USB_REQUEST_GET_STATUS = 0, + USB_REQUEST_CLEAR_FEATURE = 1, + USB_REQUEST_SET_FEATURE = 3, + USB_REQUEST_SET_ADDRESS = 5, + USB_REQUEST_GET_DESCRIPTOR = 6, + USB_REQUEST_SET_DESCRIPTOR = 7, + USB_REQUEST_GET_CONFIGURATION = 8, + USB_REQUEST_SET_CONFIGURATION = 9, + USB_REQUEST_GET_INTERFACE = 10, + USB_REQUEST_SET_INTERFACE = 11, + USB_REQUEST_SYNCH_FRAME = 12, + + USB_REQUEST_GET_MS_DESCRIPTOR = 0x99, + + USB_REQUEST_BULK_GET_MAX_LUN = 0xFE, + USB_REQUEST_BULK_RESET = 0xFF +} usb_standard_req_t; + +typedef enum { + USB_FEATURE_ENDPOINT_HALT = 0, + USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +} usb_get_status_req_t; + +typedef enum { + USB_STATUS_EP_OK = 0, + USB_STATUS_EP_HALTED = 1, + + USB_STATUS_DEV_SELF_POWERED = 1, + USB_STATUS_DEV_REMOTE_WAKE = 2, +} usb_set_clear_feature_req_t; + +typedef enum { + USB_XFER_DIR_OUT = 0, + USB_XFER_DIR_IN = 1, +} usb_xfer_dir_t; + +typedef enum { + USB_SPEED_LOW = 0, + USB_SPEED_FULL = 1, + USB_SPEED_HIGH = 2, + USB_SPEED_SUPER = 3, +} usb_speed_t; + +typedef enum { + USB_XFER_TYPE_CONTROL = 0, + USB_XFER_TYPE_ISOCHRONOUS = 1, + USB_XFER_TYPE_BULK = 2, + USB_XFER_TYPE_INTERRUPT = 3, +} usb_xfer_type_t; + +typedef struct _dTD_t +{ + vu32 next_dTD; + vu32 info; + vu32 pages[5]; + vu32 reserved; +} dTD_t; + +typedef struct _dQH_t +{ + vu32 ep_capabilities; + vu32 curr_dTD_ptr; + vu32 next_dTD_ptr; + vu32 token; + vu32 buffers[5]; // hmmm. + vu32 reserved; + vu32 setup[2]; + vu32 gap[4]; +} dQH_t; + +typedef struct _usbd_t +{ + volatile dTD_t dtds[4 * 4]; // 4 dTD per endpoint. + volatile dQH_t *qhs; + int ep_configured[4]; + int ep_bytes_requested[4]; +} usbd_t; + +typedef struct _usb_ctrl_setup_t +{ + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} usb_ctrl_setup_t; + +typedef struct _usbd_controller_t +{ + u32 port_speed; + t210_usb2d_t *regs; + usb_ctrl_setup_t control_setup; + usb_desc_t *desc; + usb_gadget_type type; + u8 configuration_set; + u8 usb_phy_ready; + u8 configuration; + u8 interface; + u8 max_lun; + u8 max_lun_set; + u8 bulk_reset_req; + u8 hid_report_sent; + bool charger_detect; +} usbd_controller_t; + +u8 usb_serial_string_descriptor[26] = +{ + 26, 0x03, + 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, + '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 +}; + +u8 usb_lang_id_string_descriptor[] = +{ + 4, 3, + 0x09, 0x04 +}; + +usbd_t *usbdaemon; + +usbd_controller_t *usbd_otg; +usbd_controller_t usbd_usb_otg_controller_ctxt; + +bool usb_init_done = false; + +u8 *usb_ep0_ctrl_buf = (u8 *)USB_EP_CONTROL_BUF_ADDR; + +static int _usbd_reset_usb_otg_phy_device_mode() +{ + usbd_otg->usb_phy_ready = 0; + + // Clear UTMIP reset. + USB(USB1_IF_USB_SUSP_CTRL) &= ~SUSP_CTRL_UTMIP_RESET; + + // Wait for PHY clock to get validated. + u32 retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return 1; + usleep(1); + } + usbd_otg->usb_phy_ready = 1; + + // Clear all device addresses, enabled setup requests and transmit events. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Set controller mode to idle. + usbd_otg->regs->usbmode &= ~USB2D_USBMODE_CM_MASK; + + // Reset the controller. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RESET; + + // Wait for the reset to complete. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->usbcmd & USB2D_USBCMD_RESET) + { + retries--; + if (!retries) + return 2; + usleep(1); + } + + // Wait for PHY clock to get validated after reset. + retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Set controller to Device mode. + usbd_otg->regs->usbmode = (usbd_otg->regs->usbmode & ~USB2D_USBMODE_CM_MASK) | USB2D_USBMODE_CM_DEVICE; + + // Wait for the selected mode to be enabled. + retries = 100000; // 200ms timeout. + while ((usbd_otg->regs->usbmode & USB2D_USBMODE_CM_MASK) != USB2D_USBMODE_CM_DEVICE) + { + retries--; + if (!retries) + return 4; + usleep(1); + } + + // Disable all interrupts. + usbd_otg->regs->usbintr = 0; + + // Set the ID pullup and disable all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_ID_PULLUP; + + // Clear all relevant interrupt statuses. + usbd_otg->regs->usbsts = + USB2D_USBSTS_UI | USB2D_USBSTS_UEI | USB2D_USBSTS_PCI | + USB2D_USBSTS_FRI | USB2D_USBSTS_SEI | USB2D_USBSTS_AAI | + USB2D_USBSTS_URI | USB2D_USBSTS_SRI | USB2D_USBSTS_SLI; + + // Disable and clear all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_IRQ_STS_MASK; + + // Clear EP0, EP1, EP2 setup requests. + usbd_otg->regs->endptsetupstat = 7; //TODO: Shouldn't this be endptsetupstat = endptsetupstat? + + // Set all interrupts to immediate. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_ITC_MASK; + + return 0; +} + +static void _usb_charger_detect() +{ + // Charger detect init. + usbd_otg->charger_detect = 0; + bool charger_detect_enable = FUSE(FUSE_RESERVED_SW) & 0x10; // Disabled on Switch production. + if (charger_detect_enable) + { + usbd_otg->charger_detect |= 1; + // Configure detect pin. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO1) &= ~(PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_config(GPIO_PORT_V, GPIO_PIN_3, GPIO_MODE_GPIO); + + // Configure charger pin. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) &= + ~(PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_config(GPIO_PORT_CC, GPIO_PIN_5, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); + + // Enable charger. + if (gpio_read(GPIO_PORT_V, GPIO_PIN_3)) + { + usbd_otg->charger_detect |= 2; + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH); + usbd_otg->charger_detect |= 0x100; + USB(USB1_UTMIP_BAT_CHRG_CFG0) = BAT_CHRG_CFG0_OP_SRC_EN; // Clears UTMIP_PD_CHRG and enables charger detect. + usleep(5000); + } + } +} + +int usb_device_init() +{ + if (usb_init_done) + return 0; + + // Configure PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) = CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) | 0x20000000; // Disable reference clock. + u32 pllu_cfg = (((((CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) >> 8 << 8) | 2) & 0xFFFF00FF) | ((0x19 << 8) & 0xFFFF)) & 0xFFE0FFFF) | (1<< 16) | 0x1000000; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | 0x40000000; // Enable. + + // Wait for PLL to stabilize. + u32 timeout = (u32)TMR(TIMERUS_CNTR_1US) + 1300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & (1 << 27))) // PLL_LOCK. + if ((u32)TMR(TIMERUS_CNTR_1US) > timeout) + break; + usleep(10); + + // Enable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) | 0x2600000 | 0x800000; + + // Enable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = (1 << 22); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = (1 << 22); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = (1 << 22); + usleep(2); + + // Clear XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = (1 << 14); + + // Enable USB PHY and reset for programming. + u32 usb_susp_ctrl = USB(USB1_IF_USB_SUSP_CTRL); + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_RESET; + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_PHY_ENB | SUSP_CTRL_UTMIP_RESET; + + // Disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) &= 0xFFFFFFFD; + usleep(10); + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) &= 0xBFFFFFFF; + + // Set B_SESS_VLD. + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x1000; + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x800; + + // Set UTMIPLL dividers and enable it. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | 0x190000 | 0x100; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | 0x600000; // Set delay count for 38.4Mhz osc crystal. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = ((CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) & 0x7FFF000) | 0x8000 | 0x177) & 0xFFFFAFFF; + + // Wait for UTMIPLL to stabilize. + u32 retries = 10; // Wait 20us + while (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0x80000000) && retries) + { + usleep(1); + retries--; + } + + // Configure UTMIP Transceiver Cells. + u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); + USB(USB1_UTMIP_XCVR_CFG0) = (((USB(USB1_UTMIP_XCVR_CFG0) & 0xFFFFFFF0) | (fuse_usb_calib & 0xF)) & 0xFE3FFFFF) | ((fuse_usb_calib & 0x3F) << 25 >> 29 << 22); + USB(USB1_UTMIP_XCVR_CFG1) = (USB(USB1_UTMIP_XCVR_CFG1) & 0xFFC3FFFF) | ((fuse_usb_calib << 21) >> 28 << 18); + USB(USB1_UTMIP_XCVR_CFG3) = (USB(USB1_UTMIP_XCVR_CFG3) & 0xFFFFC1FF) | ((FUSE(FUSE_USB_CALIB_EXT) & 0x1F) << 9); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFDFFFFF; + USB(USB1_UTMIP_XCVR_CFG2) = (USB(USB1_UTMIP_XCVR_CFG2) & 0xFFFFF1FF) | 0x400; + usleep(1); + + // Configure misc UTMIP. + USB(USB1_UTMIP_DEBOUNCE_CFG0) = (USB(USB1_UTMIP_DEBOUNCE_CFG0) & 0xFFFF0000) | 0xBB80; + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFC0FF) | 0x100; // when osc is 38.4KHz + + //USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFEE7; unpatched0 + USB(USB1_UTMIP_BIAS_CFG2) |= 2; //patched0 - UTMIP_HSSQUELCH_LEVEL_NEW: 2. + USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFE67; //patched0 - FUSE_HS_IREF_CAP_CFG + USB(USB1_UTMIP_TX_CFG0) |= 0x80000; + + //USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xFFF003FF) | 0x88000 | 0x4000; unpatched1 + USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xF0F003FF) | 0x88000 | 0x4000; //patched1 - reset UTMIP_PCOUNT_UPDN_DIV: From 1 to 0. + USB(USB1_UTMIP_BIAS_CFG2) &= 0xFFFFFFF8; //patched1 - UTMIP_HSSQUELCH_LEVEL_NEW: 0 + + USB(USB1_UTMIP_HSRX_CFG1) = (USB(USB1_UTMIP_HSRX_CFG1) & 0xFFFFFFC1) | 0x12; + USB(USB1_UTMIP_MISC_CFG1) |= 0x40000000; + + // Enable crystal clock. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= 0x40000000; + // Enable USB2 tracking. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= 0x40000; + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. + + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFC03F07) | 0x78000 | 0x50; // Set delays. + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFFFFFBFF; // Disable Power down bias circuit. + usleep(1); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE) | 2; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + usleep(3); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + + // Disable USB2_TRK clock and configure UTMIP misc. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) &= 0xFFFBFFFF; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFEA) | 0x2000000 | 0x28 | 2; + usleep(1); + + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFF3FF7FF; + usleep(1); + + // Clear power downs on UTMIP ID and VBUS wake up, PD, PD2, PDZI, PDCHRP, PDDR. + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFFBFFF; // UTMIP_FORCE_PD_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFEFFFF; // UTMIP_FORCE_PD2_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFBFFFF; // UTMIP_FORCE_PDZI_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFFB; // UTMIP_FORCE_PDCHRP_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFEF; // UTMIP_FORCE_PDDR_POWERDOWN. + usleep(1); + + // AHB USB performance cfg. + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_USB_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) |= ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = + MEM_PREFETCH_ENABLE | (MEM_PREFETCH_AHB_MST_USB << 26) | (12 << 21) | 0x1000; // addr boundary 64KB + + // Set software and hardware context storage and clear it. + usbdaemon = (usbd_t *)USBD_ADDR; // Depends on USB_TD_BUFFER_PAGE_SIZE aligned address. + usbd_otg = &usbd_usb_otg_controller_ctxt; + memset(usbd_otg, 0, sizeof(usbd_controller_t)); + memset(usbdaemon, 0, sizeof(usbd_t)); + + usbd_otg->regs = (t210_usb2d_t *)USB_OTG_BASE; + usbd_otg->usb_phy_ready = 0; + + // Initialize USB PHY on the USB_OTG Controller (#1) in Device mode. + int result = _usbd_reset_usb_otg_phy_device_mode(); + usbd_otg->configuration_set = 0; + + _usb_charger_detect(); + + if (!result) + usb_init_done = true; + + return result; +} + +static void _usb_device_power_down() +{ + // Enable PHY low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_PHCD; + // Do not use any controller regs after the above! + // A reset or clear of the PHCD suspend bit must happen. + + // Power down OTG and Bias circuits. + USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 11) | (1 << 10); // UTMIP_OTGPD, UTMIP_BIASPD. + + // Power down ID detectors. + USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 23) | (1 << 22); //UTMIP_IDPD_SEL, UTMIP_IDPD_VAL. + + if (usbd_otg->charger_detect) + { + USB(USB1_UTMIP_BAT_CHRG_CFG0) = 1; //UTMIP_PD_CHRG + usbd_otg->charger_detect = 0; + } + + // Power down the UTMIP transceivers. + // UTMIP_FORCE_PDZI_POWERDOWN, UTMIP_FORCE_PD2_POWERDOWN, UTMIP_FORCE_PD_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG0) |= (1 << 18) | (1 << 16) |(1 << 14); + // UTMIP_FORCE_PDDR_POWERDOWN, UTMIP_FORCE_PDCHRP_POWERDOWN, UTMIP_FORCE_PDDISC_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG1) |= (1 << 4) | (1 << 2) | (1 << 0); + + // Keep UTMIP in reset. + USB(USB1_IF_USB_SUSP_CTRL) |= SUSP_CTRL_UTMIP_RESET; + + // Power down PD trunk. + USB(USB1_UTMIP_BIAS_CFG1) |= (1 << 0); //UTMIP_FORCE_PDTRK_POWERDOWN. + + // Force UTMIP_PLL power down. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 14); // UTMIP_FORCE_PLL_ENABLE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 12); // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= (1 << 4) | (1 << 0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 16); // UTMIP_FORCE_PLLU_POWERDOWN. + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + + // Enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 2; + + // Set XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = (1 << 14); + + // Disable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = (1 << 22); + + // Completely disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x40000000; // Disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~0x20000000; // Enable reference clock. + + usb_init_done = false; +} + +static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall) +{ + stall &= 1; + if (direction == USB_XFER_DIR_IN) + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16); + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + } + else + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_RX_EP_STALL) | stall; + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + } +} + +void usbd_end(bool reset_ep, bool only_controller) +{ + if (reset_ep) + { + usbd_flush_endpoint(USB_EP_ALL); + _usbd_stall_reset_ep1(0, USB_EP_CFG_RESET); // EP1 Bulk IN. + _usbd_stall_reset_ep1(1, USB_EP_CFG_RESET); // EP1 Bulk OUT. + //TODO: what about EP0 simultaneous in/out reset. + + usbd_otg->configuration = 0; + usbd_otg->interface = 0; + usbd_otg->configuration_set = 0; + usbd_otg->max_lun_set = 0; + } + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Enable PHY auto low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS; + + if (!only_controller) + _usb_device_power_down(); +} + +void usb_device_stall_ep1_bulk_out() +{ + _usbd_stall_reset_ep1(USB_XFER_DIR_OUT, USB_EP_CFG_STALL); +} + +void usb_device_stall_ep1_bulk_in() +{ + _usbd_stall_reset_ep1(USB_XFER_DIR_IN, USB_EP_CFG_STALL); +} + +int usbd_get_max_pkt_length(int endpoint) +{ + switch (endpoint) + { + case USB_EP_CTRL_OUT: + case USB_EP_CTRL_IN: + return 64; + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + if (usbd_otg->port_speed == 2) + return 512; + else + return 64; + default: + return 64; + } +} + +static void _usbd_initialize_ep_ctrl(u32 endpoint) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + + if (!endpoint) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + usbdaemon->qhs[endpoint].next_dTD_ptr = 1; // TERMINATE_SET + + u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16; + + if (direction == USB_XFER_DIR_IN) + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK; + if (actual_ep) + endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK; + else + endpoint_type |= USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_ENABLE; + } + else // EP Bulk OUT. + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_RX_EP_TYPE_MASK; + if (actual_ep) + { + endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK; + } + else + endpoint_type |= USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_ENABLE; + } +} + +static int _usbd_initialize_ep0() +{ + memset((void *)usbdaemon->qhs, 0, sizeof(dQH_t) * 4); // Clear all used EP queue heads. + memset((void *)usbdaemon->dtds, 0, sizeof(dTD_t) * 4); // Clear all used EP0 token heads. + + usbd_otg->regs->asynclistaddr = (u32)usbdaemon->qhs; + + _usbd_initialize_ep_ctrl(USB_EP_CTRL_OUT); + _usbd_initialize_ep_ctrl(USB_EP_CTRL_IN); + + // Disable Auto Low Power. + usbd_otg->regs->hostpc1_devlc &= ~USB2D_HOSTPC1_DEVLC_ASUS; + + // Initiate an attach event. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RUN; + + u32 retries = 100000; // 200ms timeout. + while (!(usbd_otg->regs->usbcmd & USB2D_USBCMD_RUN)) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + return 0; +} + +// static void _disable_usb_wdt4() +// { +// if (TIMER_WDT4_STATUS & 1)// active +// { +// TIMER_TMR0_TMR_PTV &= 0x7FFFFFFF; // Disable timer +// TIMER_WDT4_UNLOCK_PATTERN = 0xC45A; // Alow writes to disable counter bit. +// TIMER_WDT4_COMMAND |= 2; // Disable counter +// TIMER_TMR0_TMR_PCR |= 0x40000000;// INTR_CLR +// } +// } + +int usbd_flush_endpoint(u32 endpoint) +{ + + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + u32 reg_mask = endpoint; + + // Flash all endpoints or 1. + if (endpoint != USB_EP_ALL) + { + if (direction == USB_XFER_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + } + usbd_otg->regs->endptflush = reg_mask; + + u32 retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptflush & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Wait for the endpoint to finish all transactions (buffer not ready). + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptstatus & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Wait for the endpoint to clear the primed status. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptprime & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + return 0; +} + +static void _usbd_mark_ep_complete(u32 endpoint) +{ + u32 complete_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + usbd_flush_endpoint(endpoint); + memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4); + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + usbdaemon->ep_configured[endpoint] = 0; + usbdaemon->ep_bytes_requested[endpoint] = 0; + + if (direction == USB_XFER_DIR_IN) + complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + usbd_otg->regs->endptcomplete |= complete_bit; +} + +static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) +{ + bool status; + u32 reg_val; + u32 reg_mask; + u32 actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + if (direction == USB_XFER_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + if (actual_ep == USB_HW_EP1) + reg_val = usbd_otg->regs->endptctrl[1]; + else + reg_val = usbd_otg->regs->endptctrl[0]; + + // Check stalled status. + if (direction == USB_XFER_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL; + + if (status) + return USB_EP_STATUS_STALLED; + + // Check enabled status. + if (direction == USB_XFER_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE; + + if (!status) + return USB_EP_STATUS_DISABLED; + + // CHeck qHD error status. + u32 token_error_mask = USB_QHD_TOKEN_HALTED | USB_QHD_TOKEN_BUFFER_ERROR | USB_QHD_TOKEN_XFER_ERROR; + if (usbdaemon->qhs[endpoint].token & token_error_mask) + return USB_EP_STATUS_ERROR; + + // Check if endpoint has a request or a ready buffer. + if ((usbd_otg->regs->endptprime & reg_mask) || (usbd_otg->regs->endptstatus & reg_mask)) + return USB_EP_STATUS_ACTIVE; // RX/TX active. + + // Return idle or not configured status. + if (!usbdaemon->ep_configured[endpoint]) + return USB_EP_STATUS_NO_CONFIG; + + return USB_EP_STATUS_IDLE; +} + +static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) +{ + if (!buf) + len = 0; + + u32 prime_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + u32 length_left = len; + u32 dtd_ep_idx = endpoint * 4; + + _usbd_mark_ep_complete(endpoint); + + if (endpoint == USB_EP_CTRL_OUT) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= (max_packet_len << 16) | USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS; + usbdaemon->qhs[endpoint].next_dTD_ptr = 0; // Clear terminate bit. + //usbdaemon->qhs[endpoint].ep_capabilities |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + usbdaemon->ep_configured[endpoint] = 1; + usbdaemon->ep_bytes_requested[endpoint] = len; + + // Configure dTD. + u32 dtd_idx = 0; + do + { + if (dtd_idx) + usbdaemon->dtds[dtd_ep_idx + dtd_idx - 1].next_dTD = (u32)&usbdaemon->dtds[dtd_ep_idx + dtd_idx]; + + u32 dtd_size = MIN(length_left, USB_TD_BUFFER_MAX_SIZE); // 16KB max per dTD. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].info = (dtd_size << 16) | USB_QHD_TOKEN_ACTIVE; + // usbdaemon->dtds[dtd_ep_idx + dtd_idx].info |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + // Set buffers addresses to all page pointers. + u32 dt_buffer_offset = dtd_idx * USB_TD_BUFFER_MAX_SIZE; + for (u32 i = 0; i < 4; i++) + usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = + (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * i)]; + + //usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[5] = + // (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * 4)]; // Last buffer. Unused. + + length_left -= dtd_size; + if (length_left) + dtd_idx++; + } + while (length_left); + + // Last dTD, terminate it. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].next_dTD = 1; + + // Set first dTD address to queue head next dTD. + usbdaemon->qhs[endpoint].next_dTD_ptr |= (u32)&usbdaemon->dtds[dtd_ep_idx] & 0xFFFFFFE0; + + // Flush AHB prefetcher. + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE; + + if (direction == USB_XFER_DIR_IN) + { + prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + } + else + prime_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + // Prime endpoint. + usbd_otg->regs->endptprime |= prime_bit; // USB2_CONTROLLER_USB2D_ENDPTPRIME. + + int res = 0; + usb_ep_status_t ep_status; + if (sync) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status == USB_EP_STATUS_ACTIVE) + { + u32 retries = 1000000; // Timeout 2s. + while (retries) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status != USB_EP_STATUS_ACTIVE) + { + if (ep_status == USB_EP_STATUS_DISABLED) + res = 28; + goto out; + } + retries--; + usleep(1); + } + res = 3; + } + else if (ep_status == USB_EP_STATUS_DISABLED) + res = 28; +out: + if (res) + _usbd_mark_ep_complete(endpoint); + else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE) + res = 26; + } + + if (direction == USB_XFER_DIR_OUT) + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + return res; +} + +static int _usbd_ep_ack(usb_ep_t ep) +{ + return _usbd_ep_operation(ep, NULL, 0, true); +} + +static void _usbd_set_ep0_stall() +{ + // EP Control endpoints must be always stalled together. + usbd_otg->regs->endptctrl[0] = + USB2D_ENDPTCTRL_TX_EP_ENABLE | USB2D_ENDPTCTRL_TX_EP_STALL | + USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL; +} + +void usbd_set_ep_stall(u32 endpoint, int ep_stall) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + if (ep_stall) + { + if (direction == USB_XFER_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT. + } + else + { + if (direction == USB_XFER_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT. + } +} + +static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, int *ep_stall) +{ + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wLength = usbd_otg->control_setup.wLength; + + bool valid_interface = _wIndex == usbd_otg->interface; + bool valid_len = _bRequest == USB_REQUEST_BULK_GET_MAX_LUN ? 1 : 0; + + if (!valid_interface || _wValue != 0 || _wLength != valid_len) + { + *ep_stall = 1; + return; + } + + switch (_bRequest) + { + case USB_REQUEST_BULK_RESET: + _usbd_ep_ack(USB_EP_CTRL_IN); + usbd_otg->bulk_reset_req = 1; + break; // DELAYED_STATUS; + case USB_REQUEST_BULK_GET_MAX_LUN: + *transmit_data = 1; + descriptor[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported. + usbd_otg->max_lun_set = 1; + break; + default: + *ep_stall = 1; + break; + } +} + +static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, int *size, int *ep_stall) +{ + u8 descriptor_type = usbd_otg->control_setup.wValue >> 8; + u8 descriptor_subtype = usbd_otg->control_setup.wValue & 0xFF; + + switch (descriptor_type) + { + case USB_DESCRIPTOR_DEVICE: + { +/* + u32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV); + usb_device_descriptor.idProduct = (soc_rev >> 8) & 0xFF; // chip_id. + usb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM. + usb_device_descriptor.bcdDevice = (soc_rev >> 16) & 0xF; // MINORREV. + usb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV. +*/ + *descriptor = usbd_otg->desc->dev; + *size = usbd_otg->desc->dev->bLength; + *transmit_data = 1; + return; + } + case USB_DESCRIPTOR_CONFIGURATION: + if (usbd_otg->type == USB_GADGET_UMS) + { + if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; + } + else // Full speed. 64 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x40; + } + } + else + { + usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_otg->desc->cfg; + if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x200; + tmp->endpoint[1].wMaxPacketSize = 0x200; + } + else // Full speed. 64 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x40; + tmp->endpoint[1].wMaxPacketSize = 0x40; + } + } + *descriptor = usbd_otg->desc->cfg; + *size = usbd_otg->desc->cfg->config.wTotalLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_STRING: + switch (descriptor_subtype) + { + case 1: + *descriptor = usbd_otg->desc->vendor; + *size = usbd_otg->desc->vendor[0]; + break; + case 2: + *descriptor = usbd_otg->desc->product; + *size = usbd_otg->desc->product[0]; + break; + case 3: + *descriptor = usb_serial_string_descriptor; + *size = usb_serial_string_descriptor[0]; + break; + case 0xEE: + *descriptor = usbd_otg->desc->ms_os; + *size = usbd_otg->desc->ms_os->bLength; + break; + default: + *descriptor = usb_lang_id_string_descriptor; + *size = 4; + break; + } + *transmit_data = 1; + return; + case USB_DESCRIPTOR_DEVICE_QUALIFIER: + if (!usbd_otg->desc->dev_qual) + goto exit; + *descriptor = usbd_otg->desc->dev_qual; + *size = usbd_otg->desc->dev_qual->bLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + if (!usbd_otg->desc->cfg_other) + goto exit; + if (usbd_otg->port_speed == 2) + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; + } + else + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x200; + } + if ((usbd_otg->charger_detect & 1) && (usbd_otg->charger_detect & 2)) + usbd_otg->desc->cfg_other->config.bMaxPower = 500 / 2; + *descriptor = usbd_otg->desc->cfg_other; + *size = usbd_otg->desc->cfg_other->config.wTotalLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: + *descriptor = usbd_otg->desc->dev_bot; + *size = usbd_otg->desc->dev_bot->wTotalLength; + *transmit_data = 1; + return; + default: + *transmit_data = 0; + *ep_stall = 1; + return; + } +exit: + *transmit_data = 0; + *ep_stall = 1; + return; +} + +static int _usbd_handle_set_request(int *ep_stall) +{ + int ret = 0; + u8 bRequest = usbd_otg->control_setup.bRequest; + if (bRequest == USB_REQUEST_SET_ADDRESS) + { + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + + // Set USB address for device mode. + if (!ret) + usbd_otg->regs->periodiclistbase = (usbd_otg->regs->periodiclistbase & 0x1FFFFFF) | ((usbd_otg->control_setup.wValue & 0xFF) << 25); + } + else if (bRequest == USB_REQUEST_SET_CONFIGURATION) + { + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!ret) + { + usbd_otg->configuration = usbd_otg->control_setup.wValue; + _usbd_initialize_ep_ctrl(USB_EP_BULK_OUT); + _usbd_initialize_ep_ctrl(USB_EP_BULK_IN); + usbd_otg->configuration_set = 1; + } + } + else + *ep_stall = 1; + + return ret; +} + +static int _usbd_handle_ep0_control_transfer() +{ + int direction; + + int ret = 0; + bool transmit_data = 0; + u8 *descriptor = (u8 *)USB_DESCRIPTOR_ADDR; + int size = 0; + int ep_stall = 0; + + u8 _bmRequestType = usbd_otg->control_setup.bmRequestType; + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wLength = usbd_otg->control_setup.wLength; + + //gfx_printf("%02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); + + switch (_bmRequestType) + { + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): + ret = _usbd_handle_set_request(&ep_stall); + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!ret) + usbd_otg->interface = _wValue; + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + switch (_bRequest) + { + case USB_REQUEST_CLEAR_FEATURE: + case USB_REQUEST_SET_FEATURE: + if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) + { + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + direction = 2; + break; + case USB_EP_ADDR_CTRL_IN: + direction = 3; + break; + case USB_EP_ADDR_BULK_OUT: + direction = 0; + break; + case USB_EP_ADDR_BULK_IN: + direction = 1; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + _usbd_stall_reset_ep1(direction, USB_EP_CFG_RESET); + else + _usbd_stall_reset_ep1(direction, USB_EP_CFG_STALL); + + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + + break; + default: + ep_stall = 1; + break; + } + break; + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + break; + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): + switch (_bRequest) + { + case USB_REQUEST_GET_STATUS: + descriptor[0] = USB_STATUS_DEV_SELF_POWERED; + descriptor[1] = 0; // No support for remove wake up. + transmit_data = 1; + size = 2; + break; + case USB_REQUEST_GET_DESCRIPTOR: + _usbd_handle_get_descriptor(&transmit_data, (void **)&descriptor, &size, &ep_stall); + break; + case USB_REQUEST_GET_CONFIGURATION: + descriptor = (u8 *)&usbd_otg->configuration; + size = _wLength; + transmit_data = 1; + break; + default: + ep_stall = 1; + break; + } + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): + if (_bRequest == USB_REQUEST_GET_INTERFACE) + { + descriptor = (void *)&usbd_otg->interface; + } + else if (_bRequest == USB_REQUEST_GET_STATUS) + { + memset(descriptor, 0, _wLength); + } + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->type > USB_GADGET_UMS) + { + if (usbd_otg->type == USB_GADGET_HID_GAMEPAD) + { + descriptor = (u8 *)&hid_report_descriptor_jc; + _wLength = sizeof(hid_report_descriptor_jc); + } + else // USB_GADGET_HID_TOUCHPAD + { + descriptor = (u8 *)&hid_report_descriptor_touch; + _wLength = sizeof(hid_report_descriptor_touch); + } + + usbd_otg->hid_report_sent = 1; + } + else + { + ep_stall = 1; + break; + } + + size = _wLength; + transmit_data = 1; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + if (_bRequest == USB_REQUEST_GET_STATUS) + { + int ep_req; + switch (_wIndex) + { + case 0: + ep_req = 0; + break; + case 1: + ep_req = 2; + break; + case 0x80: + ep_req = 1; + break; + case 0x81: + ep_req = 3; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + size = _wLength; + memset(descriptor, 0, size); + + if (_usbd_get_ep_status(ep_req) == USB_EP_STATUS_STALLED) + descriptor[0] = USB_STATUS_EP_HALTED; + else + descriptor[0] = USB_STATUS_EP_OK; + + transmit_data = 1; + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + memset(descriptor, 0, _wLength); + + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + size = _wLength; + break; + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR): + if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) + { + switch (_wIndex) + { + case USB_DESCRIPTOR_MS_COMPAT_ID: + descriptor = (u8 *)usbd_otg->desc->ms_cid; + size = usbd_otg->desc->ms_cid->dLength; + transmit_data = 1; + break; + case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: + descriptor = (u8 *)usbd_otg->desc->mx_ext; + size = usbd_otg->desc->mx_ext->dLength; + transmit_data = 1; + break; + default: + ep_stall = 1; + break; + } + } + else + ep_stall = 1; + break; + + default: + ep_stall = 1; + break; + } + + // Transmit data to HOST if any. + if (transmit_data) + { + memcpy(usb_ep0_ctrl_buf, descriptor, size); + + if (_wLength < size) + size = _wLength; + ret = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, true); + if (!ret) + ret = _usbd_ep_ack(USB_EP_CTRL_OUT); + } + +out: + if (ep_stall) + _usbd_set_ep0_stall(); + + return ret; +} + +static int _usbd_ep0_initialize() +{ + bool enter = false; + if (usbd_otg->configuration_set) + enter = true; + else + { + usbdaemon->qhs = (volatile dQH_t *)USB2_QH_USB2D_QH_EP_BASE; + + if (!_usbd_initialize_ep0()) + enter = true; + } + + if (enter) + { + usbd_otg->configuration_set = 0; + usbd_otg->max_lun_set = 0; + + // Timeout if cable or communication isn't started in 1.5 minutes. + u32 timer = get_tmr_ms() + 90000; + while (true) + { + u32 usb_status_irqs = usbd_otg->regs->usbsts; + + // Clear all interrupt statuses. + usbd_otg->regs->usbsts = usb_status_irqs; + + // Check if a reset was received. + if (usb_status_irqs & USB2D_USBSTS_URI) + { + //_disable_usb_wdt4(); + + // Clear all device addresses, enabled setup requests, transmit events and flush all endpoints. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + usbd_flush_endpoint(USB_EP_ALL); + } + + // Check if port change happened. + if (usb_status_irqs & USB2D_USBSTS_PCI) + usbd_otg->port_speed = (usbd_otg->regs->hostpc1_devlc & USB2D_HOSTPC1_DEVLC_PSPD_MASK) >> 25; + + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + if (_usbd_handle_ep0_control_transfer()) + break; + } + if (usbd_otg->configuration_set) + return 0; + + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return 2; + } + } + + return 3; +} + +int usb_device_ep0_initialize(usb_gadget_type type) +{ + switch (type) + { + case USB_GADGET_UMS: + usbd_otg->desc = &usb_gadget_ums_descriptors; + break; + case USB_GADGET_HID_GAMEPAD: + usbd_otg->desc = &usb_gadget_hid_jc_descriptors; + break; + case USB_GADGET_HID_TOUCHPAD: + usbd_otg->desc = &usb_gadget_hid_touch_descriptors; + break; + } + + usbd_otg->type = type; + + int result = _usbd_ep0_initialize(); + if (result) + result = 8; + return result; +} + +int usbd_handle_ep0_pending_control_transfer() +{ + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + _usbd_handle_ep0_control_transfer(); + memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE); + } + + if (usbd_otg->bulk_reset_req) + { + usbd_otg->bulk_reset_req = 0; + return 1; + } + + return 0; +} + +static usb_ep_status_t _usbd_get_ep1_status(usb_xfer_dir_t dir) +{ + usb_ep_t ep; + if (dir == USB_XFER_DIR_OUT) + ep = USB_EP_BULK_OUT; + else + ep = USB_EP_BULK_IN; + return _usbd_get_ep_status(ep); +} + +int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int result = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync); + + if (sync && bytes_read) + { + if (result) + *bytes_read = 0; + else + *bytes_read = len; + } + + return result; +} + +int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read) +{ + if (len > USB_EP_BULK_OUT_MAX_XFER) + len = USB_EP_BULK_OUT_MAX_XFER; + + int result; + u32 bytes = 0; + *bytes_read = 0; + u8 *buf_curr = buf; + + while (len) + { + u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); + + result = usb_device_read_ep1_out(buf_curr, len_ep, &bytes, true); + if (!result) + { + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; + } + else + break; + } + + return result; +} + +static int _usbd_get_ep1_out_bytes_read() +{ + if (_usbd_get_ep_status(2) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[2] - (usbdaemon->qhs[2].token >> 16)); +} + +int usb_device_ep1_out_reading_finish(u32 *pending_bytes) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_XFER_DIR_OUT); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_pending_control_transfer(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_out_bytes_read(); + + if (ep_status == USB_EP_STATUS_IDLE) + return 0; + else if (ep_status == USB_EP_STATUS_DISABLED) + return 28; + else + return 26; +} + +int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int result = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync); + + if (sync && bytes_written) + { + if (result) + *bytes_written = 0; + else + *bytes_written = len; + } + + return result; +} + +static int _usbd_get_ep1_in_bytes_written() +{ + if (_usbd_get_ep_status(3) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[3] - (usbdaemon->qhs[3].token >> 16)); +} + +int usb_device_ep1_in_writing_finish(u32 *pending_bytes) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_XFER_DIR_IN); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_pending_control_transfer(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_in_bytes_written(); + + if (ep_status == USB_EP_STATUS_IDLE) + return 0; + else if (ep_status == USB_EP_STATUS_DISABLED) + return 28; + + usb_device_stall_ep1_bulk_out(); + return 26; +} + +bool usb_device_get_suspended() +{ + u32 suspended = usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP; + return (suspended ? true : false); +} + +u32 usb_device_get_port_status() +{ + return (usbd_otg->regs->portsc1); +} + +bool usb_device_get_max_lun(u8 max_lun) +{ + // Timeout if get MAX_LUN request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + usbd_otg->max_lun = max_lun; + + while (!usbd_otg->max_lun_set) + { + usbd_handle_ep0_pending_control_transfer(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + return false; +} + +bool usb_device_get_hid_report() +{ + // Timeout if get GET_HID_REPORT request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + while (!usbd_otg->hid_report_sent) + { + usbd_handle_ep0_pending_control_transfer(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + return false; +} diff --git a/bdk/usb/usbd.h b/bdk/usb/usbd.h new file mode 100644 index 0000000..82a73e2 --- /dev/null +++ b/bdk/usb/usbd.h @@ -0,0 +1,86 @@ +/* + * USB Device 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 . + */ + +#ifndef _USB_H_ +#define _USB_H_ + +#include + +#define USB_TD_BUFFER_PAGE_SIZE 0x1000 +#define USB_TD_BUFFER_MAX_SIZE (USB_TD_BUFFER_PAGE_SIZE * 4) +//#define USB_HW_BUFFER_5_PAGES 0x5000 +#define USB_EP_BUFFER_1_TD (USB_TD_BUFFER_MAX_SIZE) +#define USB_EP_BUFFER_2_TD (USB_TD_BUFFER_MAX_SIZE * 2) +#define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4) +#define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) + +typedef struct _usb_ctxt_t +{ + u32 type; + u32 partition; + u32 offset; + u32 sectors; + u32 ro; + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usb_ctxt_t; + +typedef enum _usb_hid_type +{ + USB_HID_GAMEPAD, + USB_HID_TOUCHPAD +} usb_hid_type; + +typedef enum _usb_gadget_type +{ + USB_GADGET_UMS, + USB_GADGET_HID_GAMEPAD, + USB_GADGET_HID_TOUCHPAD +} usb_gadget_type; + +typedef enum +{ + USB_EP_CTRL_OUT = 0, // EP0. + USB_EP_CTRL_IN = 1, // EP0. + USB_EP_BULK_OUT = 2, // EP1. + USB_EP_BULK_IN = 3, // EP1. + USB_EP_ALL = 0xFFFFFFFF +} usb_ep_t; + +int usbd_flush_endpoint(u32 ep); +void usbd_set_ep_stall(u32 endpoint, int ep_stall); +int usbd_get_max_pkt_length(int endpoint); +int usbd_handle_ep0_pending_control_transfer(); +void usbd_end(bool reset_ep, bool only_controller); +int usb_device_init(); +int usb_device_ep0_initialize(usb_gadget_type type); +int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync); +int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read); +int usb_device_ep1_out_reading_finish(u32 *pending_bytes); +int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync); +int usb_device_ep1_in_writing_finish(u32 *pending_bytes); +bool usb_device_get_suspended(); + +int usb_device_gadget_ums(usb_ctxt_t *usbs); +int usb_device_gadget_hid(usb_ctxt_t *usbs); +bool usb_device_get_max_lun(u8 max_lun); +bool usb_device_get_hid_report(); +u32 usb_device_get_port_status(); + +#endif \ No newline at end of file diff --git a/source/utils/aarch64_util.h b/bdk/utils/aarch64_util.h similarity index 98% rename from source/utils/aarch64_util.h rename to bdk/utils/aarch64_util.h index a5002c0..456bfc8 100644 --- a/source/utils/aarch64_util.h +++ b/bdk/utils/aarch64_util.h @@ -18,7 +18,7 @@ #ifndef _ARM64_H_ #define _ARM64_H_ -#include "types.h" +#include #define LSL0 0 #define LSL16 16 diff --git a/source/utils/btn.c b/bdk/utils/btn.c similarity index 85% rename from source/utils/btn.c rename to bdk/utils/btn.c index 5a1d024..9ffe275 100644 --- a/source/utils/btn.c +++ b/bdk/utils/btn.c @@ -16,11 +16,11 @@ */ #include "btn.h" -#include "../soc/i2c.h" -#include "../soc/gpio.h" -#include "../soc/t210.h" -#include "util.h" -#include "../power/max77620.h" +#include +#include +#include +#include +#include u8 btn_read() { @@ -70,6 +70,22 @@ u8 btn_wait() } u8 btn_wait_timeout(u32 time_ms, u8 mask) +{ + u32 timeout = get_tmr_ms() + time_ms; + u8 res = btn_read() & mask; + + while (get_tmr_ms() < timeout) + { + if (res == mask) + break; + else + res = btn_read() & mask; + }; + + return res; +} + +u8 btn_wait_timeout_single(u32 time_ms, u8 mask) { u8 single_button = mask & BTN_SINGLE; mask &= ~BTN_SINGLE; diff --git a/source/utils/btn.h b/bdk/utils/btn.h similarity index 92% rename from source/utils/btn.h rename to bdk/utils/btn.h index 4f6b4d2..f284748 100644 --- a/source/utils/btn.h +++ b/bdk/utils/btn.h @@ -18,7 +18,7 @@ #ifndef _BTN_H_ #define _BTN_H_ -#include "types.h" +#include #define BTN_POWER (1 << 0) #define BTN_VOL_DOWN (1 << 1) @@ -29,5 +29,6 @@ u8 btn_read(); u8 btn_read_vol(); u8 btn_wait(); u8 btn_wait_timeout(u32 time_ms, u8 mask); +u8 btn_wait_timeout_single(u32 time_ms, u8 mask); #endif diff --git a/source/utils/dirlist.c b/bdk/utils/dirlist.c similarity index 82% rename from source/utils/dirlist.c rename to bdk/utils/dirlist.c index 2bb8eaf..5732683 100644 --- a/source/utils/dirlist.c +++ b/bdk/utils/dirlist.c @@ -17,11 +17,11 @@ #include #include -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/types.h" +#include +#include +#include -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles) +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs) { u8 max_entries = 61; @@ -40,12 +40,18 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile res = f_readdir(&dir, &fno); if (res || !fno.fname[0]) break; - if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + + bool curr_parse = parse_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR); + + if (curr_parse) { - strcpy(dir_entries + (k * 256), fno.fname); - k++; - if (k > (max_entries - 1)) - break; + if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + strcpy(dir_entries + (k * 256), fno.fname); + k++; + if (k > (max_entries - 1)) + break; + } } } f_closedir(&dir); diff --git a/source/utils/dirlist.h b/bdk/utils/dirlist.h similarity index 91% rename from source/utils/dirlist.h rename to bdk/utils/dirlist.h index 4fb9af7..32197f3 100644 --- a/source/utils/dirlist.h +++ b/bdk/utils/dirlist.h @@ -14,6 +14,6 @@ * along with this program. If not, see . */ -#include "../utils/types.h" +#include -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles); +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs); diff --git a/source/config/ini.c b/bdk/utils/ini.c similarity index 96% rename from source/config/ini.c rename to bdk/utils/ini.c index 4c200dd..538435e 100644 --- a/source/config/ini.c +++ b/bdk/utils/ini.c @@ -18,9 +18,9 @@ #include #include "ini.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/dirlist.h" +#include +#include +#include static char *_strdup(char *str) { @@ -81,7 +81,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) // Get all ini filenames. if (is_dir) { - filelist = dirlist(filename, "*.ini", false); + filelist = dirlist(filename, "*.ini", false, false); if (!filelist) { free(filename); diff --git a/source/config/ini.h b/bdk/utils/ini.h similarity index 95% rename from source/config/ini.h rename to bdk/utils/ini.h index dffbe86..571d19d 100644 --- a/source/config/ini.h +++ b/bdk/utils/ini.h @@ -18,8 +18,8 @@ #ifndef _INI_H_ #define _INI_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include +#include #define INI_CHOICE 3 #define INI_CAPTION 5 diff --git a/source/utils/list.h b/bdk/utils/list.h similarity index 98% rename from source/utils/list.h rename to bdk/utils/list.h index 80e4498..ece5402 100644 --- a/source/utils/list.h +++ b/bdk/utils/list.h @@ -18,7 +18,7 @@ #ifndef _LIST_H_ #define _LIST_H_ -#include "types.h" +#include /*! Initialize list. */ #define LIST_INIT(name) link_t name = {&name, &name} diff --git a/source/utils/sprintf.c b/bdk/utils/sprintf.c similarity index 100% rename from source/utils/sprintf.c rename to bdk/utils/sprintf.c diff --git a/source/utils/sprintf.h b/bdk/utils/sprintf.h similarity index 100% rename from source/utils/sprintf.h rename to bdk/utils/sprintf.h diff --git a/source/utils/types.h b/bdk/utils/types.h similarity index 82% rename from source/utils/types.h rename to bdk/utils/types.h index 7a7d847..62f9eef 100644 --- a/source/utils/types.h +++ b/bdk/utils/types.h @@ -27,21 +27,6 @@ #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) -// #define KB_FIRMWARE_VERSION_100_200 0 -// #define KB_FIRMWARE_VERSION_300 1 -// #define KB_FIRMWARE_VERSION_301 2 -// #define KB_FIRMWARE_VERSION_400 3 -// #define KB_FIRMWARE_VERSION_500 4 -// #define KB_FIRMWARE_VERSION_600 5 -// #define KB_FIRMWARE_VERSION_620 6 -// #define KB_FIRMWARE_VERSION_700 7 -// #define KB_FIRMWARE_VERSION_810 8 -// #define KB_FIRMWARE_VERSION_900 9 -// #define KB_FIRMWARE_VERSION_910 10 -// #define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 - -// #define HOS_PKG11_MAGIC 0x31314B50 - #define COLOR_RED 0xFFE70000 #define COLOR_ORANGE 0xFFFF8C00 #define COLOR_YELLOW 0xFFFFFF40 diff --git a/source/utils/util.c b/bdk/utils/util.c similarity index 86% rename from source/utils/util.c rename to bdk/utils/util.c index a6455fe..dd10781 100644 --- a/source/utils/util.c +++ b/bdk/utils/util.c @@ -15,17 +15,16 @@ * along with this program. If not, see . */ -#include "util.h" -#include "../gfx/di.h" -#include "../mem/heap.h" -#include "../mem/minerva.h" -#include "../power/max77620.h" -#include "../rtc/max77620-rtc.h" -#include "../soc/bpmp.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../storage/nx_sd.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define USE_RTC_TIMER @@ -135,24 +134,16 @@ void panic(u32 val) void reboot_normal() { - bpmp_mmu_disable(); - - sd_unmount(); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; + sd_end(); + reconfig_hw_workaround(false, 0); panic(0x21); // Bypass fuse programming in package1. } void reboot_rcm() { - bpmp_mmu_disable(); - - sd_unmount(); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; + sd_end(); + reconfig_hw_workaround(false, 0); PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; @@ -163,10 +154,8 @@ void reboot_rcm() void power_off() { - sd_unmount(); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; + sd_end(); + reconfig_hw_workaround(false, 0); // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); diff --git a/source/utils/util.h b/bdk/utils/util.h similarity index 92% rename from source/utils/util.h rename to bdk/utils/util.h index d918194..948e02c 100644 --- a/source/utils/util.h +++ b/bdk/utils/util.h @@ -18,13 +18,14 @@ #ifndef _UTIL_H_ #define _UTIL_H_ -#include "types.h" -#include "../mem/minerva.h" +#include +#include typedef enum { - NYX_CFG_UMS = (1 << 6), - NYX_CFG_DUMP = (1 << 7), + NYX_CFG_BIS = (1 << 5), + NYX_CFG_UMS = (1 << 6), + NYX_CFG_DUMP = (1 << 7), } nyx_cfg_t; typedef enum diff --git a/source/config/config.c b/source/config.c similarity index 78% rename from source/config/config.c rename to source/config.c index 5028b08..7168e5b 100644 --- a/source/config/config.c +++ b/source/config.c @@ -18,16 +18,17 @@ #include #include "config.h" -#include "ini.h" -#include "../gfx/gfx.h" -#include "../gfx/tui.h" -#include "../libs/fatfs/ff.h" -#include "../soc/t210.h" -#include "../storage/nx_sd.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/util.h" +#include +#include +#include "gfx/tui.h" +#include +#include +#include +#include +#include +#include +#include +#include extern hekate_config h_cfg; @@ -37,7 +38,6 @@ void set_default_configuration() h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; h_cfg.se_keygen_done = 0; - h_cfg.sbar_time_keeping = 0; h_cfg.backlight = 100; h_cfg.autohosoff = 0; h_cfg.autonogc = 1; @@ -46,7 +46,7 @@ void set_default_configuration() h_cfg.tagline = NULL; h_cfg.errors = 0; h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; - h_cfg.rcm_patched = true; + h_cfg.rcm_patched = fuse_check_patched_rcm(); h_cfg.emummc_force_disable = false; sd_power_cycle_time_start = 0; diff --git a/source/config/config.h b/source/config.h similarity index 95% rename from source/config/config.h rename to source/config.h index 0410a7e..7833f4f 100644 --- a/source/config/config.h +++ b/source/config.h @@ -17,7 +17,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include "../utils/types.h" +#include typedef struct _hekate_config { @@ -36,7 +36,6 @@ typedef struct _hekate_config bool sept_run; bool emummc_force_disable; bool rcm_patched; - u32 sbar_time_keeping; u32 errors; } hekate_config; diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index e4abe4e..3ed440c 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -122,28 +122,28 @@ static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) }; -void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) -{ - gfx_ctxt.fb = fb; - gfx_ctxt.width = width; - gfx_ctxt.height = height; - gfx_ctxt.stride = stride; -} - void gfx_clear_grey(u8 color) { memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); } +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +{ + memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); +} + void gfx_clear_color(u32 color) { for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) gfx_ctxt.fb[i] = color; } -void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) { - memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; } void gfx_con_init() diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index 0871820..ab4ea1e 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -19,13 +19,39 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include "../../common/common_gfx.h" +#include #define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) #define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 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) +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; + void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); void gfx_clear_grey(u8 color); void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); @@ -48,8 +74,4 @@ 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_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -// Global gfx console and context. -extern gfx_ctxt_t gfx_ctxt; -extern gfx_con_t gfx_con; - #endif diff --git a/source/gfx/tui.c b/source/gfx/tui.c index 3b59569..e96a466 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -15,35 +15,28 @@ * along with this program. If not, see . */ -#include "di.h" +#include #include "tui.h" -#include "../utils/btn.h" -#include "../config/config.h" -#include "../power/max17050.h" -#include "../utils/util.h" - -#ifdef MENU_LOGO_ENABLE -extern u8 *Kc_MENU_LOGO; -#define X_MENU_LOGO 119 -#define Y_MENU_LOGO 57 -#define X_POS_MENU_LOGO 577 -#define Y_POS_MENU_LOGO 1179 -#endif //MENU_LOGO_ENABLE +#include "../config.h" +#include +#include +#include extern hekate_config h_cfg; void tui_sbar(bool force_update) { u32 cx, cy; + static u32 sbar_time_keeping = 0; - u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping; + u32 timePassed = get_tmr_s() - sbar_time_keeping; if (!force_update) if (timePassed < 5) return; u8 prevFontSize = gfx_con.fntsz; gfx_con.fntsz = 16; - h_cfg.sbar_time_keeping = get_tmr_s(); + sbar_time_keeping = get_tmr_s(); u32 battPercent = 0; int battVoltCurr = 0; @@ -103,11 +96,6 @@ void *tui_do_menu(menu_t *menu) gfx_clear_partial_grey(0x1B, 0, 1256); tui_sbar(true); -#ifdef MENU_LOGO_ENABLE - gfx_set_rect_rgb(Kc_MENU_LOGO, - X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); -#endif //MENU_LOGO_ENABLE - while (true) { gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); @@ -214,10 +202,6 @@ void *tui_do_menu(menu_t *menu) } gfx_con.fntsz = 16; gfx_clear_partial_grey(0x1B, 0, 1256); -#ifdef MENU_LOGO_ENABLE - gfx_set_rect_rgb(Kc_MENU_LOGO, - X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); -#endif //MENU_LOGO_ENABLE } tui_sbar(false); } diff --git a/source/gfx/tui.h b/source/gfx/tui.h index a503b08..6f02781 100644 --- a/source/gfx/tui.h +++ b/source/gfx/tui.h @@ -18,8 +18,8 @@ #ifndef _TUI_H_ #define _TUI_H_ -#include "../utils/types.h" -#include "gfx.h" +#include +#include #define MENT_END 0 #define MENT_HANDLER 1 diff --git a/source/hos/fss.c b/source/hos/fss.c index a68deeb..6ae5d8d 100644 --- a/source/hos/fss.c +++ b/source/hos/fss.c @@ -19,14 +19,13 @@ #include #include "fss.h" -// #include "hos.h" -#include "../config/config.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" +#include "../config.h" +#include +#include #include "../storage/emummc.h" -#include "../storage/nx_sd.h" +#include -#include "../gfx/gfx.h" +#include #define DPRINTF(...) extern hekate_config h_cfg; diff --git a/source/hos/hos.h b/source/hos/hos.h index d2c8712..4ad8747 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -20,9 +20,9 @@ #include "pkg1.h" #include "pkg2.h" -#include "../utils/types.h" -#include "../config/ini.h" -#include "../sec/tsec.h" +#include +#include +#include #include @@ -44,6 +44,7 @@ typedef struct _exo_ctxt_t { + bool fs_is_510; bool no_user_exceptions; bool user_pmu; bool *cal0_blank; @@ -52,23 +53,30 @@ typedef struct _exo_ctxt_t typedef struct _hos_eks_keys_t { - u8 dkg[0x10]; u8 mkk[0x10]; u8 fdk[0x10]; - u8 dkk[0x10]; } hos_eks_keys_t; +typedef struct _hos_eks_bis_keys_t +{ + u8 crypt[0x10]; + u8 tweak[0x10]; +} hos_eks_bis_keys_t; + typedef struct _hos_eks_mbr_t { u32 magic; - u32 enabled; - u32 sbk_low[2]; + u8 enabled[6]; + u8 enabled_bis; + u8 rsvd; + u32 sbk_low; + u8 dkg[0x10]; + u8 dkk[0x10]; hos_eks_keys_t keys[6]; - u32 magic2; - u32 rsvd2[3]; + hos_eks_bis_keys_t bis_keys[3]; } hos_eks_mbr_t; -static_assert(sizeof(hos_eks_mbr_t) == 416, "HOS EKS storage bigger than MBR!"); +static_assert(sizeof(hos_eks_mbr_t) == 336, "HOS EKS size is wrong!"); typedef struct _launch_ctxt_t { @@ -100,7 +108,7 @@ typedef struct _launch_ctxt_t bool fss0_enable_experimental; bool emummc_forced; - exo_ctxt_t exo_cfg; + exo_ctxt_t exo_ctx; ini_sec_t *cfg; } launch_ctxt_t; diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index e80f964..30bb805 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -20,7 +20,7 @@ #include #include "pkg1.h" -#include "../sec/se.h" +#include #define HASH_ORDER_100_100 { \ FS_KEY_AREA_KEY_APPLI_SOURCE, \ diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index a7d6a8d..50b4e91 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -17,7 +17,7 @@ #ifndef _PKG1_H_ #define _PKG1_H_ -#include "../utils/types.h" +#include #define FS_HEADER_KEK_SOURCE 0 #define FS_HEADER_KEY_SOURCE 1 diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index 09ebb67..b80c06d 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -19,12 +19,12 @@ #include #include "pkg2.h" -#include "../utils/aarch64_util.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../libs/compr/blz.h" +#include +#include +#include +#include -#include "../gfx/gfx.h" +#include u32 pkg2_newkern_ini1_val; u32 pkg2_newkern_ini1_start; diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index 96e8fe5..e416fba 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -18,8 +18,8 @@ #ifndef _PKG2_H_ #define _PKG2_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include +#include #define PKG2_MAGIC 0x31324B50 #define PKG2_SEC_BASE 0x80000000 @@ -47,7 +47,8 @@ typedef struct _pkg2_hdr_t u32 magic; u32 base; u32 pad0; - u16 version; + u8 pkg2_ver; + u8 bl_ver; u16 pad1; u32 sec_size[4]; u32 sec_off[4]; diff --git a/source/hos/sept.c b/source/hos/sept.c index 84d0181..fe9222f 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -16,24 +16,25 @@ #include +#include "hos.h" +#include "fss.h" #include "sept.h" -#include "../config/ini.h" -#include "../gfx/di.h" -#include "../hos/fss.h" -#include "../hos/hos.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../soc/hw_init.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include #include "../storage/nx_emmc.h" -#include "../storage/nx_sd.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/types.h" +#include +#include +#include +#include +#include -#include "../gfx/gfx.h" +#include #define PATCHED_RELOC_SZ 0x94 diff --git a/source/hos/sept.h b/source/hos/sept.h index 01bd845..086d50d 100644 --- a/source/hos/sept.h +++ b/source/hos/sept.h @@ -17,7 +17,7 @@ #ifndef _SEPT_H_ #define _SEPT_H_ -#include "../utils/types.h" +#include int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb); diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 1388713..6b2a8ef 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -92,7 +92,7 @@ static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */ + {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ }; // from SPL diff --git a/source/keys/keys.c b/source/keys/keys.c index e60c9a7..22c929e 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -16,33 +16,34 @@ #include "keys.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" +#include "../config.h" +#include +#include #include "../gfx/tui.h" #include "../hos/hos.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../mem/minerva.h" -#include "../mem/sdram.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../sec/tsec.h" -#include "../soc/fuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "../storage/emummc.h" #include "../storage/nx_emmc.h" -#include "../storage/nx_sd.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include "../storage/nx_emmc_bis.h" +#include +#include +#include +#include +#include +#include #include "key_sources.inl" #include "save.h" @@ -51,15 +52,9 @@ extern hekate_config h_cfg; -extern bool clear_cluster_cache; -extern bool lock_cluster_cache; -extern u32 cluster_cache_index; - -u32 _key_count = 0, _titlekey_count = 0; +static u32 _key_count = 0, _titlekey_count = 0; +static u32 start_time, end_time; u32 color_idx = 0; -sdmmc_storage_t storage; -emmc_part_t *system_part; -u32 start_time, end_time; #define TPRINTF(text) \ end_time = get_tmr_us(); \ @@ -90,7 +85,7 @@ static void _save_key_family(const char *name, const void *data, u32 start_key, static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key); // nca functions -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); +static void *_nca_process(u32 tweak_ks, u32 crypt_ks, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); static void _update_ctr(u8 *ctr, u32 ofs); // titlekey functions @@ -147,7 +142,7 @@ void dump_keys() { tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; - if (emummc_storage_init_mmc(&storage, &sdmmc)) { + if (emummc_storage_init_mmc(&emmc_storage, &sdmmc)) { EPRINTF("Unable to init MMC."); goto out_wait; } @@ -155,8 +150,8 @@ void dump_keys() { // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); - emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0); + emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); @@ -230,7 +225,7 @@ void dump_keys() { gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); gfx_printf("\n to /sept/payload.bak\n\n"); gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); - sdmmc_storage_end(&storage); + sdmmc_storage_end(&emmc_storage); if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) goto out_wait; } else { @@ -331,9 +326,9 @@ get_tsec: ; } // verify keyblob is not corrupt - emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); - se_aes_key_set(3, keyblob_mac_key[i], 0x10); - se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); + emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); + se_aes_key_set(10, keyblob_mac_key[i], 0x10); + se_aes_cmac(10, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); if (memcmp(keyblob_block, keyblob_mac, 0x10) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); gfx_hexdump(i, keyblob_block, 0x10); @@ -342,8 +337,8 @@ get_tsec: ; } // decrypt keyblobs - se_aes_key_set(2, keyblob_key[i], 0x10); - se_aes_crypt_ctr(2, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10); + se_aes_key_set(6, keyblob_key[i], 0x10); + se_aes_crypt_ctr(6, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10); memcpy(package1_key[i], keyblob[i] + 0x80, 0x10); memcpy(master_kek[i], keyblob[i], 0x10); @@ -360,11 +355,9 @@ get_tsec: ; minerva_periodic_training(); u32 key_generation = 0; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { - if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { - key_generation = fuse_read_odm(2) & 0x1F; - if (key_generation) - key_generation--; - } + key_generation = fuse_read_odm_keygen_rev(); + if (key_generation) + key_generation--; } if (_key_exists(device_key)) { if (key_generation) { @@ -388,10 +381,10 @@ get_tsec: ; u8 *pkg2 = NULL; pkg2_kip1_info_t *ki = NULL; - emummc_storage_set_mmc_partition(&storage, EMMC_GPP); + emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP); // Parse eMMC GPT. LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + nx_emmc_gpt_parse(&gpt, &emmc_storage); // Find package2 partition. emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); @@ -402,7 +395,7 @@ get_tsec: ; // Read in package2 header and get package2 real size. u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); + nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; free(tmp); @@ -414,7 +407,7 @@ get_tsec: ; // Read in package2. u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); pkg2 = malloc(pkg2_size_aligned); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); + nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. minerva_periodic_training(); @@ -540,18 +533,30 @@ pkg2_done: goto key_output; } - se_aes_key_set(4, header_key + 0x00, 0x10); - se_aes_key_set(5, header_key + 0x10, 0x10); - se_aes_key_set(8, bis_key[2] + 0x00, 0x10); - se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + // Set BIS keys. + // PRODINFO/PRODINFOF + se_aes_key_set(0, bis_key[0] + 0x00, 0x10); + se_aes_key_set(1, bis_key[0] + 0x10, 0x10); + // SAFE + se_aes_key_set(2, bis_key[1] + 0x00, 0x10); + se_aes_key_set(3, bis_key[1] + 0x10, 0x10); + // SYSTEM/USER + se_aes_key_set(4, bis_key[2] + 0x00, 0x10); + se_aes_key_set(5, bis_key[2] + 0x10, 0x10); - system_part = nx_emmc_part_find(&gpt, "SYSTEM"); + // Set header key for NCA decryption. + se_aes_key_set(8, header_key + 0x00, 0x10); + se_aes_key_set(9, header_key + 0x10, 0x10); + + emmc_part_t *system_part = nx_emmc_part_find(&gpt, "SYSTEM"); if (!system_part) { EPRINTF("Unable to locate System partition."); goto key_output; } - __attribute__ ((aligned (16))) FATFS emmc_fs; - if (f_mount(&emmc_fs, "emmc:", 1)) { + + nx_emmc_bis_init(system_part); + + if (f_mount(&emmc_fs, "bis:", 1)) { EPRINTF("Unable to mount system partition."); goto key_output; } @@ -564,10 +569,8 @@ pkg2_done: // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient u8 *dec_header = (u8*)malloc(0x600); - char path[100] = "emmc:/Contents/registered"; - u32 titles_found = 0, title_limit = 2, read_bytes = 0; - if (!pkg1_not_100) - title_limit = 1; + char path[100] = "bis:/Contents/registered"; + u32 titles_found = 0, read_bytes = 0, title_limit = pkg1_not_100 ? 2 : 1; u8 *temp_file = NULL; if (f_opendir(&dir, path)) { @@ -592,20 +595,20 @@ pkg2_done: goto dismount; } - path[25] = '/'; - lock_cluster_cache = true; + path[24] = '/'; + nx_emmc_bis_cache_lock(true); while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); - memcpy(path + 26, fno.fname, 36); - path[62] = 0; + memcpy(path + 25, fno.fname, 36); + path[61] = 0; if (fno.fattrib & AM_DIR) - memcpy(path + 62, "/00", 4); + memcpy(path + 61, "/00", 4); if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) continue; - if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32) { + if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 0x20, &read_bytes) || read_bytes != 0x20) { f_close(&fp); continue; } - se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); + se_aes_xts_crypt_sec(9, 8, 0, 1, dec_header + 0x200, dec_header, 0x20); // es doesn't contain es key sources on 1.0.0 if (pkg1_not_100 && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { u8 hash_order[3] = {0, 1, 2}; @@ -615,7 +618,7 @@ pkg2_done: } hash_index = 0; // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); + temp_file = (u8*)_nca_process(9, 8, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); for (u32 i = 0; i <= 0xb0; ) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { @@ -632,7 +635,7 @@ pkg2_done: temp_file = NULL; titles_found++; } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { - temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); + temp_file = (u8*)_nca_process(9, 8, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); for (u32 i = 0; i <= 0x60; i++) { se_calc_sha256(temp_hash, temp_file + i, 0x10); if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { @@ -656,7 +659,7 @@ pkg2_done: } f_closedir(&dir); free(dec_header); - lock_cluster_cache = false; + nx_emmc_bis_cache_lock(false); // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { @@ -694,7 +697,7 @@ pkg2_done: f_close(&fp); // this file is so small that parsing the savedata properly would take longer - if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { + if (f_open(&fp, "bis:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); goto get_titlekeys; } @@ -724,20 +727,14 @@ get_titlekeys: 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; - se_aes_key_set(8, bis_key[0] + 0x00, 0x10); - se_aes_key_set(9, bis_key[0] + 0x10, 0x10); - u32 buf_size = 0x40000; u8 *buffer = (u8 *)MIXD_BUF_ALIGNED; u8 keypair[0x230] = {0}; - emummc_storage_read(&storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); + emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); - se_aes_xts_crypt(9, 8, 0, 0, buffer, buffer, 0x4000, 1); - - se_aes_key_set(8, bis_key[2] + 0x00, 0x10); - se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, 1); if (_read_le_u32(buffer, 0) != 0x304C4143) { EPRINTF("CAL0 magic not found. Check BIS key 0."); @@ -762,8 +759,8 @@ get_titlekeys: memcpy(temp_key, eticket_rsa_kek, 0x10); } - se_aes_key_set(2, temp_key, 0x10); - se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); + se_aes_key_set(6, temp_key, 0x10); + se_aes_crypt_ctr(6, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; @@ -787,7 +784,7 @@ get_titlekeys: titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000); save_ctx = calloc(1, sizeof(save_ctx_t)); u8 M[0x100]; - if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { + if (f_open(&fp, "bis:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open e1 save. Skipping."); goto dismount; } @@ -797,7 +794,8 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - clear_cluster_cache = true; + + nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e1 save."); @@ -866,7 +864,7 @@ get_titlekeys: gfx_printf("\n%kPersonalized... ", colors[color_idx % 6]); u32 common_titlekey_count = _titlekey_count; - if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { + if (f_open(&fp, "bis:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open e2 save. Skipping."); goto dismount; } @@ -874,7 +872,8 @@ get_titlekeys: save_ctx->file = &fp; save_ctx->tool_ctx.action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - clear_cluster_cache = true; + + nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e2 save."); @@ -949,14 +948,13 @@ get_titlekeys: gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); dismount:; - if (save_process_success) { + if (save_process_success) save_free_contexts(save_ctx); - } - if (save_ctx) { + + if (save_ctx) free(save_ctx); - } - f_mount(NULL, "emmc:", 1); - clear_cluster_cache = true; + + f_mount(NULL, "bis:", 1); nx_emmc_gpt_free(&gpt); key_output: ; @@ -965,7 +963,7 @@ key_output: ; EPRINTF("Unable to mount SD."); goto free_buffers; } - u32 text_buffer_size = _titlekey_count * 68 < 0x4000 ? 0x4000 : _titlekey_count * 68 + 1; + u32 text_buffer_size = MAX(_titlekey_count * 68 + 1, 0x4000); text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); @@ -1067,8 +1065,10 @@ free_buffers: free(text_buffer); out_wait: - h_cfg.emummc_force_disable = emummc_load_cfg(); - emummc_storage_end(&storage); + emummc_load_cfg(); + // Ignore whether emummc is enabled. + h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; + emummc_storage_end(&emmc_storage); gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); } @@ -1116,7 +1116,7 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); } -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { +static void *_nca_process(u32 tweak_ks, u32 crypt_ks, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; u8 *temp_file = (u8*)malloc(0x400), @@ -1125,29 +1125,29 @@ static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 l free(temp_file); return NULL; } - se_aes_xts_crypt(hk_ks1, hk_ks2, 0, 1, temp_file, temp_file, 0x200, 2); + se_aes_xts_crypt(tweak_ks, crypt_ks, 0, 1, temp_file, temp_file, 0x200, 2); // both 1.x and 2.x use master_key_00 temp_file[0x20] -= temp_file[0x20] ? 1 : 0; // decrypt key area and load decrypted key area key se_aes_key_set(7, key_area_key[temp_file[7]][temp_file[0x20]], 0x10); se_aes_crypt_block_ecb(7, 0, temp_file + 0x120, temp_file + 0x120); - se_aes_key_set(2, temp_file + 0x120, 0x10); + se_aes_key_set(6, temp_file + 0x120, 0x10); for (u32 i = 0; i < 8; i++) ctr[i] = temp_file[0x347 - i]; crypt_offset = _read_le_u32(temp_file, 0x40) * 0x200 + _read_le_u32(temp_file, 0x240); read_size = 0x10; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); + _nca_fread_ctr(6, fp, temp_file, crypt_offset, read_size, ctr); num_files = _read_le_u32(temp_file, 4); string_table_size = _read_le_u32(temp_file, 8); if (!memcmp(temp_file + 0x10 + num_files * 0x18, "main.npdm", 9)) crypt_offset += _read_le_u32(temp_file, 0x18); crypt_offset += 0x10 + num_files * 0x18 + string_table_size; read_size = 0x40; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); + _nca_fread_ctr(6, fp, temp_file, crypt_offset, read_size, ctr); rodata_offset = _read_le_u32(temp_file, 0x20); void *buf = malloc(len); - _nca_fread_ctr(2, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr); + _nca_fread_ctr(6, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr); free(temp_file); return buf; @@ -1202,7 +1202,7 @@ static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_ u8 *p_out = (u8 *)masked; while (masked_size) { - u32 cur_size = masked_size > 0x20 ? 0x20 : masked_size; + u32 cur_size = MIN(masked_size, 0x20); for (u32 i = 0; i < 4; i++) hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; diff --git a/source/keys/save.c b/source/keys/save.c index ea958d3..463bb95 100644 --- a/source/keys/save.c +++ b/source/keys/save.c @@ -2,11 +2,11 @@ #include #include "save.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../utils/types.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include #define REMAP_ENTRY_LENGTH 0x20 @@ -294,10 +294,11 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) { uint32_t length = 1; uint32_t entry_index = allocation_table_block_to_entry_index(entry->next); + uint32_t offset = entry_index * SAVE_FAT_ENTRY_SIZE; - allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE); - if ((entries[0].next & 0x80000000) == 0) { - if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) { + allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + offset); + if (allocation_table_is_single_block_segment(&entries[0])) { + if (allocation_table_is_range_entry(&entries[0])) { EPRINTF("Invalid range entry in allocation table!"); return 0; } @@ -650,8 +651,8 @@ bool save_process(save_ctx_t *ctx) { } unsigned char cmac[0x10] = {}; - se_aes_key_set(3, ctx->save_mac_key, 0x10); - se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); + se_aes_key_set(10, ctx->save_mac_key, 0x10); + se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { ctx->header_cmac_validity = VALIDITY_VALID; } else { diff --git a/source/keys/save.h b/source/keys/save.h index a89a675..2e11f4a 100644 --- a/source/keys/save.h +++ b/source/keys/save.h @@ -4,7 +4,7 @@ #include #include -#include "../libs/fatfs/ff.h" +#include #define SAVE_HEADER_SIZE 0x4000 #define SAVE_FAT_ENTRY_SIZE 8 @@ -443,21 +443,62 @@ static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_inde return block_index + 1; } -static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) { - return (entry->next & 0x7FFFFFFF) == 0; +static inline int allocation_table_get_prev(allocation_table_entry_t *entry) { + return entry->prev & 0x7FFFFFFF; +} + +static inline int allocation_table_get_next(allocation_table_entry_t *entry) { + return entry->next & 0x7FFFFFFF; } static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) { return entry->prev == 0x80000000; } - -static inline int allocation_table_get_next(allocation_table_entry_t *entry) { - return entry->next & 0x7FFFFFFF; +static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) { + return (entry->next & 0x7FFFFFFF) == 0; } -static inline int allocation_table_get_prev(allocation_table_entry_t *entry) { - return entry->prev & 0x7FFFFFFF; +static inline bool allocation_table_is_multi_block_segment(allocation_table_entry_t *entry) { + return entry->next & 0x80000000; +} + +static inline void allocation_table_make_multi_block_segment(allocation_table_entry_t *entry) { + entry->next |= 0x80000000; +} + +static inline void allocation_table_make_single_block_segment(allocation_table_entry_t *entry) { + entry->next &= 0x7FFFFFFF; +} + +static inline bool allocation_table_is_single_block_segment(allocation_table_entry_t *entry) { + return (entry->next & 0x80000000) == 0; +} + +static inline void allocation_table_make_list_start(allocation_table_entry_t *entry) { + entry->prev = 0x80000000; +} + +static inline bool allocation_table_is_range_entry(allocation_table_entry_t *entry) { + return (entry->prev & 0x80000000) != 0 && entry->prev != 0x80000000; +} + +static inline void allocation_table_make_range_entry(allocation_table_entry_t *entry) { + entry->prev |= 0x80000000; +} + +static inline void allocation_table_set_next(allocation_table_entry_t *entry, int val) { + entry->next = (entry->next & 0x80000000) | val; +} + +static inline void allocation_table_set_prev(allocation_table_entry_t *entry, int val) { + entry->prev = val; +} + +static inline void allocation_table_set_range(allocation_table_entry_t *entry, int start_index, int end_index) { + entry->next = end_index; + entry->prev = start_index; + allocation_table_make_range_entry(entry); } static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 6df8e3e..bc3dc53 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -25,39 +25,15 @@ #include -#include "../../../common/memory_map.h" - -#include "diskio.h" /* FatFs lower layer API */ -#include "../../mem/heap.h" -#include "../../sec/se.h" -#include "../../storage/nx_emmc.h" -#include "../../storage/sdmmc.h" - -extern sdmmc_storage_t sd_storage; -extern sdmmc_storage_t storage; -extern emmc_part_t *system_part; - -#define MAX_CLUSTER_CACHE_ENTRIES 128 -#define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF -#define XTS_CLUSTER_SIZE 0x4000 -#define SECTORS_PER_CLUSTER 0x20 - -typedef struct { - u32 cluster_num; // index of the cluster in the partition - u32 visit_count; // used for debugging/access analysis - u8 dirty; // has been modified without writeback flag - u8 align[7]; - u8 cluster[XTS_CLUSTER_SIZE]; // the cached cluster itself -} cluster_cache_t; - -static cluster_cache_t *cluster_cache = (cluster_cache_t *)RAM_DISK_ADDR; -u32 cluster_cache_index = 0; -u32 *cluster_lookup = (u32 *)(RAM_DISK_ADDR + MAX_CLUSTER_CACHE_ENTRIES * sizeof(cluster_cache_t)); -u8 *emmc_buffer = (u8 *)(MIXD_BUF_ALIGNED + 0x100000); - -bool clear_cluster_cache = false; -bool lock_cluster_cache = false; +#include /* FatFs lower layer API */ +#include +#include +#include "../../storage/nx_emmc_bis.h" +#include +/*-----------------------------------------------------------------------*/ +/* Get Drive Status */ +/*-----------------------------------------------------------------------*/ DSTATUS disk_status ( BYTE pdrv /* Physical drive number to identify the drive */ ) @@ -65,6 +41,9 @@ DSTATUS disk_status ( return 0; } +/*-----------------------------------------------------------------------*/ +/* Inidialize a Drive */ +/*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive number to identify the drive */ ) @@ -72,78 +51,9 @@ DSTATUS disk_initialize ( return 0; } -static inline void _gf256_mul_x_le(void *block) -{ - u32 *pdata = (u32 *)block; - u32 carry = 0; - - for (u32 i = 0; i < 4; i++) { - u32 b = pdata[i]; - pdata[i] = (b << 1) | carry; - carry = b >> 31; - } - - if (carry) - pdata[0x0] ^= 0x87; -} - -static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) -{ - int res = 0; - u8 *temptweak = (u8 *)malloc(0x10); - u32 *pdst = (u32 *)dst; - u32 *psrc = (u32 *)src; - u32 *ptweak = (u32 *)tweak; - - if (regen_tweak) { - for (int i = 0xF; i >= 0; i--) { - tweak[i] = sec & 0xFF; - sec >>= 8; - } - if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) - goto out; - } - - // tweak_exp allows us to use a saved tweak to reduce _gf256_mul_x_le calls - for (u32 i = 0; i < tweak_exp * SECTORS_PER_CLUSTER; i++) - _gf256_mul_x_le(tweak); - - memcpy(temptweak, tweak, 0x10); - - - // The reference implementation in IEEE P1619 encrypts once per AES block - // In this environment, doing so produces a lot of overhead - // Instead, we perform one single AES-ECB operation between the sector xors - - // We are assuming a 0x10-aligned sector size in this implementation. - for (u32 i = 0; i < secsize / 0x10; i++) - { - for (u32 j = 0; j < 4; j++) - pdst[j] = psrc[j] ^ ptweak[j]; - _gf256_mul_x_le(tweak); - psrc += 4; - pdst += 4; - } - se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); - - pdst = (u32 *)dst; - - memcpy(tweak, temptweak, 0x10); - for (u32 i = 0; i < secsize / 0x10; i++) - { - for (u32 j = 0; j < 4; j++) - pdst[j] = pdst[j] ^ ptweak[j]; - _gf256_mul_x_le(tweak); - pdst += 4; - } - - res = 1; - -out:; - free(temptweak); - return res; -} - +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* Physical drive number to identify the drive */ BYTE *buff, /* Data buffer to store read data */ @@ -153,91 +63,19 @@ DRESULT disk_read ( { switch (pdrv) { - case 0: + case DRIVE_SD: return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; - case 1:; - __attribute__ ((aligned (16))) static u8 tweak[0x10]; - __attribute__ ((aligned (16))) static u64 prev_cluster = -1; - __attribute__ ((aligned (16))) static u32 prev_sector = 0; - - if (cluster_cache_index == 0 || clear_cluster_cache) - { - // memset gets optimized out... - // for (u32 i = 0; i < (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER; i++) - // cluster_lookup[i] = CLUSTER_LOOKUP_EMPTY_ENTRY; - memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * 4); - cluster_cache_index = 0; - clear_cluster_cache = false; - lock_cluster_cache = false; - } - - u32 cluster = sector / SECTORS_PER_CLUSTER; - u32 aligned_sector = cluster * SECTORS_PER_CLUSTER; - u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; - u32 cluster_lookup_index = cluster_lookup[cluster]; - - if (cluster_lookup_index != CLUSTER_LOOKUP_EMPTY_ENTRY) - { - memcpy(buff, cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); - cluster_cache[cluster_lookup_index].visit_count++; - prev_sector = sector + count - 1; - prev_cluster = cluster; - return RES_OK; - } - - // Only cache single-sector reads as these are most likely to be repeated (eg. boot block, FAT directory tables) - if (count == 1 && - !lock_cluster_cache && - cluster_cache_index < MAX_CLUSTER_CACHE_ENTRIES && - cluster_lookup_index == CLUSTER_LOOKUP_EMPTY_ENTRY) - { - cluster_cache[cluster_cache_index].cluster_num = cluster; - cluster_cache[cluster_cache_index].visit_count = 1; - cluster_cache[cluster_cache_index].dirty = 0; - cluster_lookup[cluster] = cluster_cache_index; - - // Read and decrypt the whole cluster the sector resides in - if (!nx_emmc_part_read(&storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) - return RES_ERROR; - _emmc_xts(9, 8, 0, tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE); - memcpy(cluster_cache[cluster_cache_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); - memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE); - prev_cluster = -1; - prev_sector = 0; - cluster_cache_index++; - return RES_OK; - } - - if (!nx_emmc_part_read(&storage, system_part, sector, count, buff)) - return RES_ERROR; - u32 tweak_exp = 0; - bool regen_tweak = true; - if (prev_cluster != cluster) - { // Sector is in different cluster than last read - prev_cluster = cluster; - tweak_exp = sector_index_in_cluster; - } - else if (sector > prev_sector) - { // Sector is in same cluster and past last sector - // Calculates the new tweak using the saved one, reducing expensive _gf256_mul_x_le calls - tweak_exp = sector - prev_sector - 1; - regen_tweak = false; - } - else - { // Sector is in same cluster and before or same as last sector - tweak_exp = sector_index_in_cluster; - } - - // FatFs will never pull more than one 4K cluster, which is the same as the crypto 'sector' size - _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * NX_EMMC_BLOCKSIZE); - prev_sector = sector + count - 1; - return RES_OK; + case DRIVE_BIS: + return nx_emmc_bis_read(sector, count, buff); } return RES_ERROR; } +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ DRESULT disk_write ( BYTE pdrv, /* Physical drive number to identify the drive */ const BYTE *buff, /* Data to be written */ @@ -247,16 +85,19 @@ DRESULT disk_write ( { switch (pdrv) { - case 0: + case DRIVE_SD: return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; - case 1: + case DRIVE_BIS: return RES_WRPRT; } return RES_ERROR; } +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive number (0..) */ BYTE cmd, /* Control code */ diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index af35a21..4b914b3 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -168,12 +168,13 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 2 +#define FF_VOLUMES 4 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 1 -#define FF_VOLUME_STRS "sd", "emmc" +// Order is important. Any change to order, must also be reflected to diskio drive enum. +#define FF_VOLUME_STRS "sd","ram","emmc","bis" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each @@ -244,7 +245,7 @@ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2019 +#define FF_NORTC_YEAR 2020 /* The option FF_FS_NORTC switches timestamp function. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp diff --git a/source/libs/fatfs/ffsystem.c b/source/libs/fatfs/ffsystem.c index fa44f8e..6f5f435 100644 --- a/source/libs/fatfs/ffsystem.c +++ b/source/libs/fatfs/ffsystem.c @@ -5,8 +5,8 @@ /*------------------------------------------------------------------------*/ -#include "ff.h" -#include "../../mem/heap.h" +#include +#include diff --git a/source/main.c b/source/main.c index 41fe132..47aac1a 100644 --- a/source/main.c +++ b/source/main.c @@ -1,7 +1,8 @@ /* * Copyright (c) 2018 naehrwert * - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,27 +19,29 @@ #include -#include "config/config.h" -#include "config/ini.h" -#include "gfx/di.h" -#include "gfx/gfx.h" +#include "config.h" +#include +#include #include "gfx/tui.h" #include "hos/pkg1.h" -#include "libs/fatfs/ff.h" -#include "mem/heap.h" -#include "mem/minerva.h" -#include "power/max77620.h" -#include "rtc/max77620-rtc.h" -#include "soc/bpmp.h" +#include +#include +#include +#include +#include +#include +#include +#include #include "soc/hw_init.h" #include "storage/emummc.h" #include "storage/nx_emmc.h" -#include "storage/nx_sd.h" -#include "storage/sdmmc.h" -#include "utils/btn.h" -#include "utils/dirlist.h" -#include "utils/sprintf.h" -#include "utils/util.h" +#include +#include +#include +#include +#include +#include +#include #include "keys/keys.h" @@ -162,7 +165,7 @@ void launch_tools() memcpy(dir, "sd:/bootloader/payloads", 24); - filelist = dirlist(dir, NULL, false); + filelist = dirlist(dir, NULL, false, false); u32 i = 0; u32 i_off = 2; @@ -335,6 +338,11 @@ void ipl_main() // Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. heap_init(IPL_HEAP_START); +#ifdef DEBUG_UART_PORT + uart_send(DEBUG_UART_PORT, (u8 *)"hekate: Hello!\r\n", 16); + uart_wait_idle(DEBUG_UART_PORT, UART_TX_IDLE); +#endif + // Set bootloader's default configuration. set_default_configuration(); @@ -345,7 +353,7 @@ void ipl_main() display_init(); - u32 *fb = display_init_framebuffer(); + u32 *fb = display_init_framebuffer_pitch(); gfx_init_ctxt(fb, 720, 1280, 720); gfx_con_init(); @@ -355,7 +363,9 @@ void ipl_main() // Overclock BPMP. bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); - h_cfg.emummc_force_disable = emummc_load_cfg(); + emummc_load_cfg(); + // Ignore whether emummc is enabled. + h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) { @@ -364,6 +374,7 @@ void ipl_main() dump_keys(); } + // Grey out emummc option if not present. if (h_cfg.emummc_force_disable) { ment_top[1].type = MENT_CAPTION; @@ -371,6 +382,7 @@ void ipl_main() ment_top[1].handler = NULL; } + // Update key generations listed in menu. _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); while (true) diff --git a/source/mem/mc.h b/source/mem/mc.h deleted file mode 100644 index 6a28bde..0000000 --- a/source/mem/mc.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _MC_H_ -#define _MC_H_ - -#include "../utils/types.h" -#include "../mem/mc_t210.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); -void mc_config_carveout(); -void mc_config_carveout_finalize(); -void mc_enable_ahb_redirect(); -void mc_disable_ahb_redirect(); -void mc_enable(); - -#endif diff --git a/source/storage/emummc.c b/source/storage/emummc.c index eea93e5..71d62b8 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -18,33 +18,37 @@ #include #include "emummc.h" -#include "sdmmc.h" -#include "../config/config.h" -#include "../config/ini.h" -#include "../gfx/gfx.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../storage/nx_sd.h" -#include "../utils/list.h" -#include "../utils/types.h" +#include +#include "../config.h" +#include +#include +#include +#include +#include "../storage/nx_emmc.h" +#include +#include +#include extern hekate_config h_cfg; -emummc_cfg_t emu_cfg; +emummc_cfg_t emu_cfg = { 0 }; -bool emummc_load_cfg() +void emummc_load_cfg() { - sd_mount(); emu_cfg.enabled = 0; emu_cfg.path = NULL; - emu_cfg.nintendo_path = NULL; emu_cfg.sector = 0; emu_cfg.id = 0; emu_cfg.file_based_part_size = 0; emu_cfg.active_part = 0; emu_cfg.fs_ver = 0; + if (!emu_cfg.nintendo_path) + emu_cfg.nintendo_path = (char *)malloc(0x80); if (!emu_cfg.emummc_file_based_path) emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + emu_cfg.nintendo_path[0] = 0; + emu_cfg.emummc_file_based_path[0] = 0; + LIST_INIT(ini_sections); if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) { @@ -66,14 +70,51 @@ bool emummc_load_cfg() else if (!strcmp("path", kv->key)) emu_cfg.path = kv->val; else if (!strcmp("nintendo_path", kv->key)) - emu_cfg.nintendo_path = kv->val; + strcpy(emu_cfg.nintendo_path, kv->val); } break; } } - return 0; } - return 1; +} + +bool emummc_set_path(char *path) +{ + FIL fp; + bool found = false; + + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/raw_based"); + + if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + if (!f_read(&fp, &emu_cfg.sector, 4, NULL)) + if (emu_cfg.sector) + found = true; + } + else + { + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/file_based"); + + if (!f_stat(emu_cfg.emummc_file_based_path, NULL)) + { + emu_cfg.sector = 0; + emu_cfg.path = path; + + found = true; + } + } + + if (found) + { + emu_cfg.enabled = 1; + emu_cfg.id = 0; + strcpy(emu_cfg.nintendo_path, path); + strcat(emu_cfg.nintendo_path, "/Nintendo"); + } + + return found; } static int emummc_raw_get_part_off(int part_idx) @@ -93,17 +134,19 @@ static int emummc_raw_get_part_off(int part_idx) int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) { FILINFO fno; + emu_cfg.active_part = 0; + + // Always init eMMC even when in emuMMC. eMMC is needed from theh emuMMC driver anyway. if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) return 2; - if (h_cfg.emummc_force_disable) + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) return 0; - emu_cfg.active_part = 0; if (!sd_mount()) goto out; - if (emu_cfg.enabled && !emu_cfg.sector) + if (!emu_cfg.sector) { strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); strcat(emu_cfg.emummc_file_based_path, "/eMMC"); @@ -132,8 +175,10 @@ out: int emummc_storage_end(sdmmc_storage_t *storage) { - sd_unmount(); - sdmmc_storage_end(storage); + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + sdmmc_storage_end(storage); + else + sd_end(); return 1; } diff --git a/source/storage/emummc.h b/source/storage/emummc.h index 0103841..81ad123 100644 --- a/source/storage/emummc.h +++ b/source/storage/emummc.h @@ -17,8 +17,8 @@ #ifndef EMUMMC_H #define EMUMMC_H -#include "sdmmc.h" -#include "../utils/types.h" +#include +#include typedef enum { @@ -49,7 +49,8 @@ typedef struct _emummc_cfg_t extern emummc_cfg_t emu_cfg; -bool emummc_load_cfg(); +void emummc_load_cfg(); +bool emummc_set_path(char *path); int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); int emummc_storage_end(sdmmc_storage_t *storage); int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index f5765a1..be7aa4b 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -16,11 +16,15 @@ #include -#include "mbr_gpt.h" #include "nx_emmc.h" #include "emummc.h" -#include "../mem/heap.h" -#include "../utils/list.h" +#include +#include +#include + +sdmmc_t emmc_sdmmc; +sdmmc_storage_t emmc_storage; +FATFS emmc_fs; void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) { diff --git a/source/storage/nx_emmc.h b/source/storage/nx_emmc.h index 19bc1ca..5db6a1f 100644 --- a/source/storage/nx_emmc.h +++ b/source/storage/nx_emmc.h @@ -17,11 +17,12 @@ #ifndef _NX_EMMC_H_ #define _NX_EMMC_H_ -#include "sdmmc.h" -#include "../utils/types.h" -#include "../utils/list.h" +#include +#include +#include +#include -#define NX_GPT_FIRST_LBA 1 +#define NX_GPT_FIRST_LBA 1 #define NX_GPT_NUM_BLOCKS 33 #define NX_EMMC_BLOCKSIZE 512 @@ -35,6 +36,10 @@ typedef struct _emmc_part_t link_t link; } emmc_part_t; +extern sdmmc_t emmc_sdmmc; +extern sdmmc_storage_t emmc_storage; +extern FATFS emmc_fs; + void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage); void nx_emmc_gpt_free(link_t *gpt); emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name); diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c new file mode 100644 index 0000000..ec3871f --- /dev/null +++ b/source/storage/nx_emmc_bis.c @@ -0,0 +1,254 @@ +/* + * eMMC BIS driver for Nintendo Switch + * + * Copyright (c) 2019 shchmue + * 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 . + */ + +#include + +#include + +#include +#include "../storage/nx_emmc.h" +#include +#include + +#define MAX_CLUSTER_CACHE_ENTRIES 128 +#define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF +#define XTS_CLUSTER_SIZE 0x4000 +#define SECTORS_PER_CLUSTER 0x20 + +typedef struct +{ + u32 cluster_num; // index of the cluster in the partition + u32 visit_count; // used for debugging/access analysis + u8 dirty; // has been modified without writeback flag + u8 align[7]; + u8 cluster[XTS_CLUSTER_SIZE]; // the cached cluster itself +} cluster_cache_t; + +static u8 ks_crypt = 0; +static u8 ks_tweak = 0; +static u32 cluster_cache_end_index = 0; +static emmc_part_t *system_part = NULL; +static u8 *emmc_buffer = (u8 *)NX_BIS_CACHE_ADDR; +static cluster_cache_t *cluster_cache = (cluster_cache_t *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE); +static u32 *cluster_lookup = (u32 *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE + MAX_CLUSTER_CACHE_ENTRIES * sizeof(cluster_cache_t)); +static bool lock_cluster_cache = false; + +static void _gf256_mul_x_le(void *block) +{ + u32 *pdata = (u32 *)block; + u32 carry = 0; + + for (u32 i = 0; i < 4; i++) { + u32 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 31; + } + + if (carry) + pdata[0x0] ^= 0x87; +} + +static int _nx_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u32 sec, void *dst, const void *src, u32 sec_size) +{ + u32 *pdst = (u32 *)dst; + u32 *psrc = (u32 *)src; + u32 *ptweak = (u32 *)tweak; + + if (regen_tweak) + { + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(tweak_ks, 1, tweak, tweak)) + return 0; + } + + // tweak_exp allows us to use a saved tweak to reduce _gf256_mul_x_le calls. + for (u32 i = 0; i < (tweak_exp << 5); i++) + _gf256_mul_x_le(tweak); + + u8 orig_tweak[0x10]; + memcpy(orig_tweak, tweak, 0x10); + + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 4; j++) + pdst[j] = psrc[j] ^ ptweak[j]; + + _gf256_mul_x_le(tweak); + psrc += 4; + pdst += 4; + } + + if (!se_aes_crypt_ecb(crypt_ks, enc, dst, sec_size, dst, sec_size)) + return 0; + + pdst = (u32 *)dst; + ptweak = (u32 *)orig_tweak; + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 4; j++) + pdst[j] = pdst[j] ^ ptweak[j]; + + _gf256_mul_x_le(orig_tweak); + pdst += 4; + } + + return 1; +} + +static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) +{ + if (!system_part) + return 3; // Not ready. + + static u32 prev_cluster = -1; + static u32 prev_sector = 0; + static u8 tweak[0x10]; + + u32 tweak_exp = 0; + bool regen_tweak = true; + + u32 cluster = sector / SECTORS_PER_CLUSTER; + u32 aligned_sector = cluster * SECTORS_PER_CLUSTER; + u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; + u32 cluster_lookup_index = cluster_lookup[cluster]; + + if (cluster_lookup_index != CLUSTER_LOOKUP_EMPTY_ENTRY) + { + memcpy(buff, cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); + cluster_cache[cluster_lookup_index].visit_count++; + prev_sector = sector + count - 1; + prev_cluster = cluster; + return 0; // Success. + } + + // Only cache single-sector reads as these are most likely to be repeated, such as boot block and FAT directory tables. + if (count == 1 && + !lock_cluster_cache && + cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES && + cluster_lookup_index == CLUSTER_LOOKUP_EMPTY_ENTRY) + { + cluster_cache[cluster_cache_end_index].cluster_num = cluster; + cluster_cache[cluster_cache_end_index].visit_count = 1; + cluster_cache[cluster_cache_end_index].dirty = 0; + cluster_lookup[cluster] = cluster_cache_end_index; + + // Read and decrypt the whole cluster the sector resides in. + if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) + return 1; // R/W error. + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) + return 1; // R/W error. + + // Copy to cluster cache. + memcpy(cluster_cache[cluster_cache_end_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); + memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE); + prev_cluster = -1; + prev_sector = 0; + cluster_cache_end_index++; + return 0; // Success. + } + + // If not reading from or writing to cache, do a regular read and decrypt. + if (!nx_emmc_part_read(&emmc_storage, system_part, sector, count, buff)) + return 1; // R/W error. + + if (prev_cluster != cluster) // Sector in different cluster than last read. + { + prev_cluster = cluster; + tweak_exp = sector_index_in_cluster; + } + else if (sector > prev_sector) // Sector in same cluster and past last sector. + { + // Calculates the new tweak using the saved one, reducing expensive _gf256_mul_x_le calls. + tweak_exp = sector - prev_sector - 1; + regen_tweak = false; + } + else // Sector in same cluster and before or same as last sector. + tweak_exp = sector_index_in_cluster; + + // Maximum one cluster (1 XTS crypto block 16KB). + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * NX_EMMC_BLOCKSIZE)) + return 1; // R/W error. + prev_sector = sector + count - 1; + + return 0; // Success. +} + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff) +{ + int res = 1; + u8 *buf = (u8 *)buff; + u32 curr_sct = sector; + + while (count) + { + u32 sct_cnt = MIN(count, 0x20); + res = nx_emmc_bis_read_block(curr_sct, sct_cnt, buf); + if (res) + return 1; + + count -= sct_cnt; + curr_sct += sct_cnt; + buf += NX_EMMC_BLOCKSIZE * sct_cnt; + } + + return res; +} + +void nx_emmc_bis_cluster_cache_init() { + // Clear cluster lookup table and reset end index. + memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup)); + cluster_cache_end_index = 0; + lock_cluster_cache = false; +} + +void nx_emmc_bis_init(emmc_part_t *part) +{ + system_part = part; + + nx_emmc_bis_cluster_cache_init(); + + switch (part->index) + { + case 0: // PRODINFO. + case 1: // PRODINFOF. + ks_crypt = 0; + ks_tweak = 1; + break; + case 8: // SAFE. + ks_crypt = 2; + ks_tweak = 3; + break; + case 9: // SYSTEM. + case 10: // USER. + ks_crypt = 4; + ks_tweak = 5; + break; + } +} + +// Set cluster cache lock according to arg. +void nx_emmc_bis_cache_lock(bool lock) +{ + lock_cluster_cache = lock; +} diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h new file mode 100644 index 0000000..fc59fd5 --- /dev/null +++ b/source/storage/nx_emmc_bis.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019 shchmue + * 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 . + */ + +#ifndef NX_EMMC_BIS_H +#define NX_EMMC_BIS_H + +#include "../storage/nx_emmc.h" +#include + +typedef struct _nx_emmc_cal0_spk_t +{ + u16 unk0; + u16 unk1; + u16 eq_bw_lop; + u16 eq_gn_lop; + u16 eq_fc_bp1; + u16 eq_bw_bp1; + u16 eq_gn_bp1; + u16 eq_fc_bp2; + u16 eq_bw_bp2; + u16 eq_gn_bp2; + u16 eq_fc_bp3; + u16 eq_bw_bp3; + u16 eq_gn_bp3; + u16 eq_fc_bp4; + u16 eq_bw_bp4; + u16 eq_gn_bp4; + u16 eq_fc_hip1; + u16 eq_gn_hip1; + u16 eq_fc_hip2; + u16 eq_bw_hip2; + u16 eq_gn_hip2; + u16 eq_pre_vol; + u16 eq_pst_vol; + u16 eq_ctrl2; + u16 eq_ctrl1; + u16 drc_agc_2; + u16 drc_agc_3; + u16 drc_agc_1; + u16 spk_vol; + u16 hp_vol; + u16 dac1_min_vol_spk; + u16 dac1_max_vol_spk; + u16 dac1_min_vol_hp; + u16 dac1_max_vol_hp; + u16 in1_in2; + u16 adc_vol_min; + u16 adc_vol_max; + u8 unk4[16]; +} __attribute__((packed)) nx_emmc_cal0_spk_t; + +typedef struct _nx_emmc_cal0_t +{ + u32 magic; // 'CAL0'. + u32 version; + u32 body_size; + u16 model; + u16 update_cnt; + u8 pad_crc16_0[0x10]; + u8 body_sha256[0x20]; + char cfg_id1[0x1E]; + u8 crc16_pad1[2]; + u8 rsvd0[0x20]; + u32 wlan_cc_num; + u32 wlan_cc_last; + char wlan_cc[128][3]; + u8 crc16_pad2[8]; + u8 wlan_mac[6]; + u8 crc16_pad3[2]; + u8 rsvd1[8]; + u8 bd_mac[6]; + u8 crc16_pad4[2]; + u8 rsvd2[8]; + u8 acc_offset[6]; + u8 crc16_pad5[2]; + u8 acc_scale[6]; + u8 crc16_pad6[2]; + u8 gyro_offset[6]; + u8 crc16_pad7[2]; + u8 gyro_scale[6]; + u8 crc16_pad8[2]; + char serial_number[0x18]; + u8 crc16_pad9[8]; + + u8 ecc_p256_device_key[0x30]; + u8 crc16_pad10[0x10]; + u8 ecc_p256_device_cert[0x180]; + u8 crc16_pad11[0x10]; + u8 ecc_p233_device_key[0x30]; + u8 crc16_pad12[0x10]; + u8 ecc_p33_device_cert[0x180]; + u8 crc16_pad13[0x10]; + u8 ecc_p256_ticket_key[0x30]; + u8 crc16_pad14[0x10]; + u8 ecc_p256_ticket_cert[0x180]; + u8 crc16_pad15[0x10]; + u8 ecc_p233_ticket_key[0x30]; + u8 crc16_pad16[0x10]; + u8 ecc_p33_ticket_cert[0x180]; + u8 crc16_pad17[0x10]; + u8 ssl_key[0x110]; + u8 crc16_pad18[0x10]; + u32 ssl_cert_size; + u8 crc16_pad19[0xC]; + u8 ssl_cert[0x800]; + u8 ssl_sha256[0x20]; + u8 random_number[0x1000]; + u8 random_number_sha256[0x20]; + u8 gc_key[0x110]; + u8 crc16_pad20[0x10]; + u8 gc_cert[0x400]; + u8 gc_cert_sha256[0x20]; + u8 rsa2048_eticket_key[0x220]; + u8 crc16_pad21[0x10]; + u8 rsa2048_eticket_cert[0x240]; + u8 crc16_pad22[0x10]; + + char battery_lot[0x1E]; + u8 crc16_pad23[2]; + nx_emmc_cal0_spk_t spk_cal; + u8 spk_cal_rsvd[0x800 - sizeof(nx_emmc_cal0_spk_t)]; + u8 crc16_pad24[0x10]; + u32 region_code; + u8 crc16_pad25[0xC]; + + u8 amiibo_key[0x50]; + u8 crc16_pad26[0x10]; + u8 amiibo_ecqv_cert[0x14]; + u8 crc16_pad27[0xC]; + u8 amiibo_ecqdsa_cert[0x70]; + u8 crc16_pad28[0x10]; + u8 amiibo_ecqv_bls_key[0x40]; + u8 crc16_pad29[0x10]; + u8 amiibo_ecqv_bls_cert[0x20]; + u8 crc16_pad30[0x10]; + u8 amiibo_ecqv_bls_root_cert[0x90]; + u8 crc16_pad31[0x10]; + + u32 product_model; // 1: Nx, 2: Copper, 4: Hoag. + u8 crc16_pad32[0xC]; + u8 home_menu_scheme_main_color[6]; + u8 crc16_pad33[0xA]; + u32 lcd_bl_brightness_mapping[3]; // Floats. Normally 100%, 0% and 2%. + u8 crc16_pad34[0x4]; + + u8 ext_ecc_b233_device_key[0x50]; + u8 crc16_pad35[0x10]; + u8 ext_ecc_p256_eticket_key[0x50]; + u8 crc16_pad36[0x10]; + u8 ext_ecc_b233_eticket_key[0x50]; + u8 crc16_pad37[0x10]; + u8 ext_ecc_rsa2048_eticket_key[0x240]; + u8 crc16_pad38[0x10]; + u8 ext_ssl_key[0x130]; + u8 crc16_pad39[0x10]; + u8 ext_gc_key[0x130]; + u8 crc16_pad40[0x10]; + + u32 lcd_vendor; + u8 crc16_pad41[0xC]; + + // 5.0.0 and up. + u8 ext_rsa2048_device_key[0x240]; + u8 crc16_pad42[0x10]; + u8 rsa2048_device_cert[0x240]; + u8 crc16_pad43[0x10]; + + u8 usbc_pwr_src_circuit_ver; + u8 crc16_pad44[0xF]; + + // 9.0.0 and up. + u32 home_menu_scheme_sub_color; + u8 crc16_pad45[0xC]; + u32 home_menu_scheme_bezel_color; + u8 crc16_pad46[0xC]; + u32 home_menu_scheme_main_color1; + u8 crc16_pad47[0xC]; + u32 home_menu_scheme_main_color2; + u8 crc16_pad48[0xC]; + u32 home_menu_scheme_main_color3; + u8 crc16_pad49[0xC]; + + u8 analog_stick_type_l; + u8 crc16_pad50[0xF]; + u8 analog_stick_param_l[0x12]; + u8 crc16_pad51[0xE]; + u8 analog_stick_cal_l[0x9]; + u8 crc16_pad52[0x7]; + u8 analog_stick_type_r; + u8 crc16_pad53[0xF]; + u8 analog_stick_param_r[0x12]; + u8 crc16_pad54[0xE]; + u8 analog_stick_cal_r[0x9]; + u8 crc16_pad55[0x7]; + u8 console_6axis_sensor_type; + u8 crc16_pad56[0xF]; + u8 console_6axis_sensor_hor_off[0x6]; + u8 crc16_pad57[0xA]; + + // 6.0.0 and up. + u8 battery_ver; + u8 crc16_pad58[0x1F]; + + // 9.0.0 and up. + u32 home_menu_scheme_model; + u8 crc16_pad59[0xC]; + + // 10.0.0 and up. + u8 console_6axis_sensor_mount_type; +} __attribute__((packed)) nx_emmc_cal0_t; + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff); +void nx_emmc_bis_cluster_cache_init(); +void nx_emmc_bis_init(emmc_part_t *part); +void nx_emmc_bis_cache_lock(bool lock); + +#endif \ No newline at end of file diff --git a/source/storage/nx_sd.c b/source/storage/nx_sd.c index 0a791ad..fa284fa 100644 --- a/source/storage/nx_sd.c +++ b/source/storage/nx_sd.c @@ -15,21 +15,50 @@ * along with this program. If not, see . */ -#include "nx_sd.h" -#include "sdmmc.h" -#include "sdmmc_driver.h" -#include "../gfx/gfx.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" +#include +#include +#include +#include +#include +#include static bool sd_mounted = false; +static u16 sd_errors[3] = { 0 }; // Init and Read/Write errors. static u32 sd_mode = SD_UHS_SDR82; - sdmmc_t sd_sdmmc; sdmmc_storage_t sd_storage; FATFS sd_fs; +void sd_error_count_increment(u8 type) +{ + switch (type) + { + case SD_ERROR_INIT_FAIL: + sd_errors[0]++; + break; + case SD_ERROR_RW_FAIL: + sd_errors[1]++; + break; + case SD_ERROR_RW_RETRY: + sd_errors[2]++; + break; + } +} + +u16 *sd_get_error_count() +{ + return sd_errors; +} + +bool sd_get_card_removed() +{ + if (!sdmmc_get_sd_inserted()) + return true; + + return false; +} + u32 sd_get_mode() { return sd_mode; @@ -85,10 +114,15 @@ bool sd_initialize(bool power_cycle) sd_mode = SD_UHS_SDR82; break; } - else if (sd_mode == SD_INIT_FAIL) - break; else - res = !sd_init_retry(true); + { + sd_errors[SD_ERROR_INIT_FAIL]++; + + if (sd_mode == SD_INIT_FAIL) + break; + else + res = !sd_init_retry(true); + } } sdmmc_storage_end(&sd_storage); @@ -130,9 +164,11 @@ bool sd_mount() return false; } -void sd_unmount() +static void _sd_deinit() { - sd_mode = SD_UHS_SDR82; + if (sd_mode == SD_INIT_FAIL) + sd_mode = SD_UHS_SDR82; + if (sd_mounted) { f_mount(NULL, "", 1); @@ -141,6 +177,9 @@ void sd_unmount() } } +void sd_unmount() { _sd_deinit(); } +void sd_end() { _sd_deinit(); } + void *sd_file_read(const char *path, u32 *fsize) { FIL fp; From bd09f5418dfea28f60c9af0f5698251da07404bd Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 26 Jun 2020 14:49:42 -0600 Subject: [PATCH 077/166] Use cal0 struct, improve style consistency --- source/keys/keys.c | 10 +++--- source/libs/fatfs/diskio.c | 64 ++++++++++++++++++------------------ source/storage/nx_emmc_bis.c | 6 ++-- source/storage/nx_emmc_bis.h | 3 +- 4 files changed, 43 insertions(+), 40 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 22c929e..d911af8 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -736,14 +736,14 @@ get_titlekeys: se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, 1); - if (_read_le_u32(buffer, 0) != 0x304C4143) { + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)buffer; + if (cal0->magic != 0x304C4143) { EPRINTF("CAL0 magic not found. Check BIS key 0."); goto dismount; } - u32 cal_version = _read_le_u32(buffer, 4); - u32 keypair_generation = _read_le_u32(buffer, 0x3AD0); - if (cal_version <= 8) + u32 keypair_generation = cal0->ext_ecc_rsa2048_eticket_key_ver; + if (cal0->version <= 8) keypair_generation = 0; // settings zeroes this out below cal version 9 if (keypair_generation) { @@ -760,7 +760,7 @@ get_titlekeys: } se_aes_key_set(6, temp_key, 0x10); - se_aes_crypt_ctr(6, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); + se_aes_crypt_ctr(6, keypair, 0x230, cal0->ext_ecc_rsa2048_eticket_key + 0x10, 0x230, cal0->ext_ecc_rsa2048_eticket_key); u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index bc3dc53..6f3af21 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -35,74 +35,74 @@ /* Get Drive Status */ /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( - BYTE pdrv /* Physical drive number to identify the drive */ + BYTE pdrv /* Physical drive number to identify the drive */ ) { - return 0; + return 0; } /*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive number to identify the drive */ + BYTE pdrv /* Physical drive number to identify the drive */ ) { - return 0; + return 0; } /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( - BYTE pdrv, /* Physical drive number to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to read */ + BYTE pdrv, /* Physical drive number to identify the drive */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to read */ ) { - switch (pdrv) - { - case DRIVE_SD: - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + switch (pdrv) + { + case DRIVE_SD: + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; - case DRIVE_BIS: - return nx_emmc_bis_read(sector, count, buff); - } + case DRIVE_BIS: + return nx_emmc_bis_read(sector, count, buff); + } - return RES_ERROR; + return RES_ERROR; } /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_write ( - BYTE pdrv, /* Physical drive number to identify the drive */ - const BYTE *buff, /* Data to be written */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ + BYTE pdrv, /* Physical drive number to identify the drive */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to write */ ) { - switch (pdrv) - { - case DRIVE_SD: - return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + switch (pdrv) + { + case DRIVE_SD: + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; - case DRIVE_BIS: - return RES_WRPRT; - } + case DRIVE_BIS: + return RES_WRPRT; + } - return RES_ERROR; + return RES_ERROR; } /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive number (0..) */ - BYTE cmd, /* Control code */ - void *buff /* Buffer to send/receive control data */ + BYTE pdrv, /* Physical drive number (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ ) { - return RES_OK; + return RES_OK; } diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index ec3871f..109b666 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -54,7 +54,8 @@ static void _gf256_mul_x_le(void *block) u32 *pdata = (u32 *)block; u32 carry = 0; - for (u32 i = 0; i < 4; i++) { + for (u32 i = 0; i < 4; i++) + { u32 b = pdata[i]; pdata[i] = (b << 1) | carry; carry = b >> 31; @@ -215,7 +216,8 @@ int nx_emmc_bis_read(u32 sector, u32 count, void *buff) return res; } -void nx_emmc_bis_cluster_cache_init() { +void nx_emmc_bis_cluster_cache_init() +{ // Clear cluster lookup table and reset end index. memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup)); cluster_cache_end_index = 0; diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index fc59fd5..93653de 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -164,7 +164,8 @@ typedef struct _nx_emmc_cal0_t u8 ext_ecc_b233_eticket_key[0x50]; u8 crc16_pad37[0x10]; u8 ext_ecc_rsa2048_eticket_key[0x240]; - u8 crc16_pad38[0x10]; + u32 ext_ecc_rsa2048_eticket_key_ver; + u8 crc16_pad38[0xC]; u8 ext_ssl_key[0x130]; u8 crc16_pad39[0x10]; u8 ext_gc_key[0x130]; From 5ed601dd4be226707e68c1781b4db136f136f253 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 2 Jul 2020 09:42:49 -0600 Subject: [PATCH 078/166] Improve emummc semantics and error checking --- Makefile | 10 +-- bdk/memory_map.h | 1 + source/gfx/tui.c | 6 +- source/keys/keys.c | 124 ++++++++++++++++++++--------------- source/main.c | 8 ++- source/storage/emummc.c | 2 +- source/storage/nx_emmc_bis.c | 39 +++++++---- 7 files changed, 114 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index 4075925..d303560 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,11 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs .PHONY: all clean all: $(OUTPUTDIR)/$(TARGET).bin + @echo -n "Payload size is " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) + @echo $(BIN_SIZE) + @echo "Max size is 126296 Bytes." + @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi clean: @rm -rf $(BUILDDIR) @@ -57,11 +62,6 @@ clean: $(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf @mkdir -p "$(@D)" $(OBJCOPY) -S -O binary $< $@ - @echo -n "Payload size is " - $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) - @echo $(BIN_SIZE) - @echo "Max size is 126296 Bytes." - @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ diff --git a/bdk/memory_map.h b/bdk/memory_map.h index 6e92668..84f4a6d 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -79,6 +79,7 @@ #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define DRAM_MEM_HOLE_ADR 0xF6A00000 +#define NX_BIS_LOOKUP_ADR DRAM_MEM_HOLE_ADR #define DRAM_MEM_HOLE_SZ 0x8140000 /* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */ #define DRAM_START2 0xFEB40000 diff --git a/source/gfx/tui.c b/source/gfx/tui.c index e96a466..79be716 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -86,7 +86,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) gfx_con_setpos(cx, cy); // Update status bar. - tui_sbar(false); + // tui_sbar(false); } void *tui_do_menu(menu_t *menu) @@ -94,7 +94,7 @@ void *tui_do_menu(menu_t *menu) int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF; gfx_clear_partial_grey(0x1B, 0, 1256); - tui_sbar(true); + // tui_sbar(true); while (true) { @@ -203,7 +203,7 @@ void *tui_do_menu(menu_t *menu) gfx_con.fntsz = 16; gfx_clear_partial_grey(0x1B, 0, 1256); } - tui_sbar(false); + // tui_sbar(false); } return NULL; diff --git a/source/keys/keys.c b/source/keys/keys.c index d911af8..3d7fd05 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -25,6 +25,7 @@ #include "../hos/pkg2.h" #include "../hos/sept.h" #include +#include #include #include #include @@ -46,7 +47,6 @@ #include #include "key_sources.inl" -#include "save.h" #include @@ -123,14 +123,12 @@ void dump_keys() { sd_mount(); display_backlight_brightness(h_cfg.backlight, 1000); - gfx_clear_partial_grey(0x1B, 0, 1256); + gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); - tui_sbar(true); - _key_count = 0; _titlekey_count = 0; color_idx = 0; @@ -150,8 +148,14 @@ void dump_keys() { // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); - emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0); - emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { + EPRINTF("Unable to set partition."); + goto out_wait; + } + if (!emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1)) { + EPRINTF("Unable to read pkg1."); + goto out_wait; + } const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); @@ -326,7 +330,10 @@ get_tsec: ; } // verify keyblob is not corrupt - emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); + if (!emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block)) { + EPRINTFARGS("Unable to read keyblob %x.", i); + continue; + } se_aes_key_set(10, keyblob_mac_key[i], 0x10); se_aes_cmac(10, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); if (memcmp(keyblob_block, keyblob_mac, 0x10) != 0) { @@ -381,7 +388,10 @@ get_tsec: ; u8 *pkg2 = NULL; pkg2_kip1_info_t *ki = NULL; - emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { + EPRINTF("Unable to set partition."); + goto out_wait; + } // Parse eMMC GPT. LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &emmc_storage); @@ -596,7 +606,6 @@ pkg2_done: } path[24] = '/'; - nx_emmc_bis_cache_lock(true); while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); memcpy(path + 25, fno.fname, 36); @@ -659,7 +668,6 @@ pkg2_done: } f_closedir(&dir); free(dec_header); - nx_emmc_bis_cache_lock(false); // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { @@ -732,7 +740,10 @@ get_titlekeys: u8 keypair[0x230] = {0}; - emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); + if (!emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer)) { + EPRINTF("Unable to read PRODINFO."); + goto dismount; + } se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, 1); @@ -777,9 +788,9 @@ get_titlekeys: se_rsa_key_set(0, N, 0x100, D, 0x100); - u32 br = buf_size; + u64 br = buf_size; u32 file_tkey_count = 0; - u64 total_br = 0; + u64 offset = 0; rights_ids = (u8 *)(MIXD_BUF_ALIGNED + 0x40000); titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000); save_ctx = calloc(1, sizeof(save_ctx_t)); @@ -792,48 +803,52 @@ get_titlekeys: u32 pct = 0, last_pct = 0; save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; + save_ctx->action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); + if (!save_process_success) { EPRINTF("Failed to process e1 save."); f_close(&fp); goto dismount; } - char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; - char ticket_list_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket_list.bin"; - allocation_table_storage_ctx_t fat_storage; - save_fs_list_entry_t entry = {0, "", {0}, 0}; - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + char ticket_bin_path[0x40] = "/ticket.bin"; + char ticket_list_bin_path[0x40] = "/ticket_list.bin"; + save_data_file_ctx_t ticket_file; + + if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket_list.bin in e1."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + break; file_tkey_count++; } } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + + if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket.bin in e1 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - total_br = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + + offset = 0; + br = buf_size; + + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { pct = _titlekey_count * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { @@ -855,7 +870,6 @@ get_titlekeys: save_free_contexts(save_ctx); save_process_success = false; memset(save_ctx, 0, sizeof(save_ctx_t)); - memset(&fat_storage, 0, sizeof(allocation_table_storage_ctx_t)); gfx_con_setpos(0, save_y); TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); @@ -870,10 +884,9 @@ get_titlekeys: } save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; + save_ctx->action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e2 save."); @@ -881,40 +894,41 @@ get_titlekeys: goto dismount; } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket_list.bin in e2 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - total_br = 0; + offset = 0; file_tkey_count = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + br = buf_size; + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + break; file_tkey_count++; } } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + + if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket.bin in e2 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - - total_br = 0; + offset = 0; pct = 0; last_pct = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + br = buf_size; + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { pct = (_titlekey_count - common_titlekey_count) * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { @@ -947,7 +961,7 @@ get_titlekeys: TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); -dismount:; +dismount: ; if (save_process_success) save_free_contexts(save_ctx); @@ -1068,9 +1082,11 @@ out_wait: emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; + emu_cfg.enabled = !h_cfg.emummc_force_disable; emummc_storage_end(&emmc_storage); - gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); + gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); + gfx_clear_grey(0x1B); } static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { diff --git a/source/main.c b/source/main.c index 47aac1a..d654fad 100644 --- a/source/main.c +++ b/source/main.c @@ -265,6 +265,7 @@ out: void dump_sysnand() { h_cfg.emummc_force_disable = true; + emu_cfg.enabled = false; b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } @@ -273,7 +274,7 @@ void dump_emunand() { if (h_cfg.emummc_force_disable) return; - emu_cfg.enabled = 1; + emu_cfg.enabled = true; b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } @@ -366,11 +367,14 @@ void ipl_main() emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; + emu_cfg.enabled = !h_cfg.emummc_force_disable; if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) { - if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) + if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) { h_cfg.emummc_force_disable = true; + emu_cfg.enabled = false; + } dump_keys(); } diff --git a/source/storage/emummc.c b/source/storage/emummc.c index 71d62b8..5253edc 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -276,7 +276,7 @@ int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) emu_cfg.active_part = partition; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - sdmmc_storage_set_mmc_partition(storage, partition); + return sdmmc_storage_set_mmc_partition(storage, partition); else if (emu_cfg.sector) return 1; else diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 109b666..ae8454d 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -21,12 +21,13 @@ #include +#include #include #include "../storage/nx_emmc.h" #include #include -#define MAX_CLUSTER_CACHE_ENTRIES 128 +#define MAX_CLUSTER_CACHE_ENTRIES 32768 #define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF #define XTS_CLUSTER_SIZE 0x4000 #define SECTORS_PER_CLUSTER 0x20 @@ -46,7 +47,8 @@ static u32 cluster_cache_end_index = 0; static emmc_part_t *system_part = NULL; static u8 *emmc_buffer = (u8 *)NX_BIS_CACHE_ADDR; static cluster_cache_t *cluster_cache = (cluster_cache_t *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE); -static u32 *cluster_lookup = (u32 *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE + MAX_CLUSTER_CACHE_ENTRIES * sizeof(cluster_cache_t)); +static u32 *cluster_lookup_buf = NULL; +static u32 *cluster_lookup = NULL; static bool lock_cluster_cache = false; static void _gf256_mul_x_le(void *block) @@ -125,6 +127,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) static u32 prev_cluster = -1; static u32 prev_sector = 0; static u8 tweak[0x10]; + u8 cache_tweak[0x10]; u32 tweak_exp = 0; bool regen_tweak = true; @@ -144,10 +147,8 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) } // Only cache single-sector reads as these are most likely to be repeated, such as boot block and FAT directory tables. - if (count == 1 && - !lock_cluster_cache && - cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES && - cluster_lookup_index == CLUSTER_LOOKUP_EMPTY_ENTRY) + if (!lock_cluster_cache && + cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES) { cluster_cache[cluster_cache_end_index].cluster_num = cluster; cluster_cache[cluster_cache_end_index].visit_count = 1; @@ -157,14 +158,12 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) // Read and decrypt the whole cluster the sector resides in. if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) return 1; // R/W error. - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) return 1; // R/W error. // Copy to cluster cache. memcpy(cluster_cache[cluster_cache_end_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); - memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE); - prev_cluster = -1; - prev_sector = 0; + memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE * count); cluster_cache_end_index++; return 0; // Success. } @@ -218,8 +217,26 @@ int nx_emmc_bis_read(u32 sector, u32 count, void *buff) void nx_emmc_bis_cluster_cache_init() { + u32 cluster_lookup_size = (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup); + + if (cluster_lookup_buf) + free(cluster_lookup_buf); + + // Check if carveout protected, in case of old hwinit (pre 4.0.0) chainload. + *(vu32 *)NX_BIS_LOOKUP_ADR = 0; + if (*(vu32 *)NX_BIS_LOOKUP_ADR != 0) + { + cluster_lookup_buf = (u32 *)malloc(cluster_lookup_size + 0x2000); + cluster_lookup = (u32 *)ALIGN((u32)cluster_lookup_buf, 0x1000); + } + else + { + cluster_lookup_buf = NULL; + cluster_lookup = (u32 *)NX_BIS_LOOKUP_ADR; + } + // Clear cluster lookup table and reset end index. - memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup)); + memset(cluster_lookup, -1, cluster_lookup_size); cluster_cache_end_index = 0; lock_cluster_cache = false; } From acc11300e5044fec0cdbfcbc23d016e347e274c1 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 2 Jul 2020 13:05:22 -0600 Subject: [PATCH 079/166] main: Read key generation from bct instead of pkg1 --- source/main.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/source/main.c b/source/main.c index d654fad..f88a91c 100644 --- a/source/main.c +++ b/source/main.c @@ -23,7 +23,6 @@ #include #include #include "gfx/tui.h" -#include "hos/pkg1.h" #include #include #include @@ -298,31 +297,27 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) sdmmc_t sdmmc; sdmmc_storage_t storage; sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); - u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + u8 *bct = (u8 *)malloc(NX_EMMC_BLOCKSIZE); sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + sdmmc_storage_read(&storage, 0x2200 / NX_EMMC_BLOCKSIZE, 1, bct); sdmmc_storage_end(&storage); - if (pkg1_id) - sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + sprintf(sysnand_label + 36, "% 3d", bct[0x130] - 1); ment_top[0].caption = sysnand_label; if (h_cfg.emummc_force_disable) { - free(pkg1); + free(bct); return; } emummc_storage_init_mmc(&storage, &sdmmc); - memset(pkg1, 0, NX_EMMC_BLOCKSIZE); + memset(bct, 0, NX_EMMC_BLOCKSIZE); emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); - pkg1_id = pkg1_identify(pkg1); + emummc_storage_read(&storage, 0x2200 / NX_EMMC_BLOCKSIZE, 1, bct); emummc_storage_end(&storage); - if (pkg1_id) - sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); - free(pkg1); + sprintf(emunand_label + 36, "% 3d", bct[0x130] - 1); + free(bct); ment_top[1].caption = emunand_label; } From 25aa483bd55562c750648437713bfd232569b74c Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 2 Jul 2020 14:10:44 -0600 Subject: [PATCH 080/166] nx_emmc_bis: Implement bis write --- source/libs/fatfs/diskio.c | 2 +- source/storage/nx_emmc_bis.c | 142 ++++++++++++++++++++++++++++++----- source/storage/nx_emmc_bis.h | 2 + 3 files changed, 127 insertions(+), 19 deletions(-) diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 6f3af21..43c5b7d 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -89,7 +89,7 @@ DRESULT disk_write ( return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; case DRIVE_BIS: - return RES_WRPRT; + return nx_emmc_bis_write(sector, count, buff); } return RES_ERROR; diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index ae8454d..85d9a96 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -41,12 +41,19 @@ typedef struct u8 cluster[XTS_CLUSTER_SIZE]; // the cached cluster itself } cluster_cache_t; +typedef struct +{ + u8 emmc_buffer[XTS_CLUSTER_SIZE]; + cluster_cache_t cluster_cache[]; +} bis_cache_t; + static u8 ks_crypt = 0; static u8 ks_tweak = 0; +static u8 cache_filled = 0; +static u32 dirty_cluster_count = 0; static u32 cluster_cache_end_index = 0; static emmc_part_t *system_part = NULL; -static u8 *emmc_buffer = (u8 *)NX_BIS_CACHE_ADDR; -static cluster_cache_t *cluster_cache = (cluster_cache_t *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE); +static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR; static u32 *cluster_lookup_buf = NULL; static u32 *cluster_lookup = NULL; static bool lock_cluster_cache = false; @@ -119,6 +126,59 @@ static int _nx_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u8 *tweak, return 1; } +static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool force_flush) +{ + if (!system_part) + return 3; // Not ready. + + u8 tweak[0x10]; + u32 cluster = sector / SECTORS_PER_CLUSTER; + u32 aligned_sector = cluster * SECTORS_PER_CLUSTER; + u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; + u32 cluster_lookup_index = cluster_lookup[cluster]; + bool is_cached = cluster_lookup_index != CLUSTER_LOOKUP_EMPTY_ENTRY; + + // Write to cached cluster. + if (is_cached) + { + if (buff) + memcpy(bis_cache->cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, buff, count * NX_EMMC_BLOCKSIZE); + else + buff = bis_cache->cluster_cache[cluster_lookup_index].cluster; + bis_cache->cluster_cache[cluster_lookup_index].visit_count++; + if (bis_cache->cluster_cache[cluster_lookup_index].dirty == 0) + dirty_cluster_count++; + bis_cache->cluster_cache[cluster_lookup_index].dirty = 1; + if (!force_flush) + return 0; // Success. + + // Reset args to trigger a full cluster flush to emmc. + sector_index_in_cluster = 0; + sector = aligned_sector; + count = SECTORS_PER_CLUSTER; + } + + // Encrypt and write. + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 1, tweak, true, sector_index_in_cluster, cluster, bis_cache->emmc_buffer, buff, count * NX_EMMC_BLOCKSIZE) || + !nx_emmc_part_write(&emmc_storage, system_part, sector, count, bis_cache->emmc_buffer) + ) + return 1; // R/W error. + + // Mark cache entry not dirty if write succeeds. + if (is_cached) + { + bis_cache->cluster_cache[cluster_lookup_index].dirty = 0; + dirty_cluster_count--; + } + + return 0; // Success. +} + +static void _nx_emmc_bis_flush_cluster(cluster_cache_t *cache_entry) +{ + nx_emmc_bis_write_block(cache_entry->cluster_num * SECTORS_PER_CLUSTER, SECTORS_PER_CLUSTER, NULL, true); +} + static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) { if (!system_part) @@ -137,39 +197,48 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; u32 cluster_lookup_index = cluster_lookup[cluster]; + // Read from cached cluster. if (cluster_lookup_index != CLUSTER_LOOKUP_EMPTY_ENTRY) { - memcpy(buff, cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); - cluster_cache[cluster_lookup_index].visit_count++; + memcpy(buff, bis_cache->cluster_cache[cluster_lookup_index].cluster + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); + bis_cache->cluster_cache[cluster_lookup_index].visit_count++; prev_sector = sector + count - 1; prev_cluster = cluster; return 0; // Success. } - // Only cache single-sector reads as these are most likely to be repeated, such as boot block and FAT directory tables. - if (!lock_cluster_cache && - cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES) + // Cache cluster. + if (!lock_cluster_cache) { - cluster_cache[cluster_cache_end_index].cluster_num = cluster; - cluster_cache[cluster_cache_end_index].visit_count = 1; - cluster_cache[cluster_cache_end_index].dirty = 0; + // Roll the cache index over and flush if full. + if (cluster_cache_end_index >= MAX_CLUSTER_CACHE_ENTRIES) + { + cluster_cache_end_index = 0; + cache_filled = 1; + } + // Check if cache entry was previously in use in case of cache loop. + if (cache_filled == 1 && bis_cache->cluster_cache[cluster_cache_end_index].dirty == 1) + _nx_emmc_bis_flush_cluster(&bis_cache->cluster_cache[cluster_cache_end_index]); + bis_cache->cluster_cache[cluster_cache_end_index].cluster_num = cluster; + bis_cache->cluster_cache[cluster_cache_end_index].visit_count = 1; + bis_cache->cluster_cache[cluster_cache_end_index].dirty = 0; cluster_lookup[cluster] = cluster_cache_end_index; // Read and decrypt the whole cluster the sector resides in. - if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) - return 1; // R/W error. - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) + if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, bis_cache->emmc_buffer) || + !_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, bis_cache->emmc_buffer, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE) + ) return 1; // R/W error. // Copy to cluster cache. - memcpy(cluster_cache[cluster_cache_end_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); - memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE * count); + memcpy(bis_cache->cluster_cache[cluster_cache_end_index].cluster, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE); + memcpy(buff, bis_cache->emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE); cluster_cache_end_index++; return 0; // Success. } // If not reading from or writing to cache, do a regular read and decrypt. - if (!nx_emmc_part_read(&emmc_storage, system_part, sector, count, buff)) + if (!nx_emmc_part_read(&emmc_storage, system_part, sector, count, bis_cache->emmc_buffer)) return 1; // R/W error. if (prev_cluster != cluster) // Sector in different cluster than last read. @@ -187,7 +256,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) tweak_exp = sector_index_in_cluster; // Maximum one cluster (1 XTS crypto block 16KB). - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * NX_EMMC_BLOCKSIZE)) + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->emmc_buffer, count * NX_EMMC_BLOCKSIZE)) return 1; // R/W error. prev_sector = sector + count - 1; @@ -215,6 +284,27 @@ int nx_emmc_bis_read(u32 sector, u32 count, void *buff) return res; } +int nx_emmc_bis_write(u32 sector, u32 count, void *buff) +{ + int res = 1; + u8 *buf = (u8 *)buff; + u32 curr_sct = sector; + + while (count) + { + u32 sct_cnt = MIN(count, 0x20); + res = nx_emmc_bis_write_block(curr_sct, sct_cnt, buf, false); + if (res) + return 1; + + count -= sct_cnt; + curr_sct += sct_cnt; + buf += NX_EMMC_BLOCKSIZE * sct_cnt; + } + + return res; +} + void nx_emmc_bis_cluster_cache_init() { u32 cluster_lookup_size = (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup); @@ -239,6 +329,9 @@ void nx_emmc_bis_cluster_cache_init() memset(cluster_lookup, -1, cluster_lookup_size); cluster_cache_end_index = 0; lock_cluster_cache = false; + + dirty_cluster_count = 0; + cache_filled = 0; } void nx_emmc_bis_init(emmc_part_t *part) @@ -246,7 +339,7 @@ void nx_emmc_bis_init(emmc_part_t *part) system_part = part; nx_emmc_bis_cluster_cache_init(); - + switch (part->index) { case 0: // PRODINFO. @@ -266,6 +359,19 @@ void nx_emmc_bis_init(emmc_part_t *part) } } +void nx_emmc_bis_finalize() +{ + if (dirty_cluster_count == 0) + return; + + u32 limit = cache_filled == 1 ? MAX_CLUSTER_CACHE_ENTRIES : cluster_cache_end_index; + for (u32 i = 0; i < limit; i++) + { + if (bis_cache->cluster_cache[i].dirty) + _nx_emmc_bis_flush_cluster(&bis_cache->cluster_cache[i]); + } +} + // Set cluster cache lock according to arg. void nx_emmc_bis_cache_lock(bool lock) { diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 93653de..09ec063 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -225,8 +225,10 @@ typedef struct _nx_emmc_cal0_t } __attribute__((packed)) nx_emmc_cal0_t; int nx_emmc_bis_read(u32 sector, u32 count, void *buff); +int nx_emmc_bis_write(u32 sector, u32 count, void *buff); void nx_emmc_bis_cluster_cache_init(); void nx_emmc_bis_init(emmc_part_t *part); +void nx_emmc_bis_finalize(); void nx_emmc_bis_cache_lock(bool lock); #endif \ No newline at end of file From 73fce1da86c829a73b456d42d96562e0adbc1d30 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 5 Jul 2020 14:06:08 -0600 Subject: [PATCH 081/166] nx_emmc_bis: Count clusters to flush --- source/libs/fatfs/diskio.c | 2 +- source/storage/nx_emmc_bis.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 43c5b7d..1cf422d 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -89,7 +89,7 @@ DRESULT disk_write ( return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; case DRIVE_BIS: - return nx_emmc_bis_write(sector, count, buff); + return nx_emmc_bis_write(sector, count, (void *)buff); } return RES_ERROR; diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 85d9a96..22e90c3 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -365,10 +365,13 @@ void nx_emmc_bis_finalize() return; u32 limit = cache_filled == 1 ? MAX_CLUSTER_CACHE_ENTRIES : cluster_cache_end_index; - for (u32 i = 0; i < limit; i++) + u32 clusters_to_flush = dirty_cluster_count; + for (u32 i = 0; i < limit && clusters_to_flush; i++) { - if (bis_cache->cluster_cache[i].dirty) + if (bis_cache->cluster_cache[i].dirty) { _nx_emmc_bis_flush_cluster(&bis_cache->cluster_cache[i]); + clusters_to_flush--; + } } } From 49dfca45a53f5c25e87a6a59c83b188cf41fc931 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 13 Jul 2020 11:31:51 -0600 Subject: [PATCH 082/166] keys: Remove key source search, begin rewrite --- source/keys/key_sources.inl | 92 +++----- source/keys/keys.c | 446 ++++++++---------------------------- 2 files changed, 119 insertions(+), 419 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 6b2a8ef..5d2f824 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -84,6 +84,35 @@ static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VER {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */ }; +static const u8 fs_keys[13][0x20] = { + {0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}, // header key source + {0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, + 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}, // encrypted header key + {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // kak appli + {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // kak ocean + {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // kak system + {0xd8, 0x9c, 0x23, 0x6e, 0xc9, 0x12, 0x4e, 0x43, 0xc8, 0x2b, 0x03, 0x87, 0x43, 0xf9, 0xcf, 0x1b}, // save mac kek source + {0xe4, 0xcd, 0x3d, 0x4a, 0xd5, 0x0f, 0x74, 0x28, 0x45, 0xa4, 0x87, 0xe5, 0xa0, 0x63, 0xea, 0x1f}, // save mac key source + {0x04, 0x89, 0xef, 0x5d, 0x32, 0x6e, 0x1a, 0x59, 0xc4, 0xb7, 0xab, 0x8c, 0x36, 0x7a, 0xab, 0x17}, // save mac sd kek source + {0x6f, 0x64, 0x59, 0x47, 0xc5, 0x61, 0x46, 0xf9, 0xff, 0xa0, 0x45, 0xd5, 0x95, 0x33, 0x29, 0x18}, // save mac sd key source + {0x37, 0x0c, 0x34, 0x5e, 0x12, 0xe4, 0xce, 0xfe, 0x21, 0xb5, 0x8e, 0x64, 0xdb, 0x52, 0xaf, 0x35, + 0x4f, 0x2c, 0xa5, 0xa3, 0xfc, 0x99, 0x9a, 0x47, 0xc0, 0x3e, 0xe0, 0x04, 0x48, 0x5b, 0x2f, 0xd0}, // sd custom key source + {0x88, 0x35, 0x8d, 0x9c, 0x62, 0x9b, 0xa1, 0xa0, 0x01, 0x47, 0xdb, 0xe0, 0x62, 0x1b, 0x54, 0x32}, // sd card kek source + {0x58, 0x41, 0xa2, 0x84, 0x93, 0x5b, 0x56, 0x27, 0x8b, 0x8e, 0x1f, 0xc5, 0x18, 0xe9, 0x9f, 0x2b, + 0x67, 0xc7, 0x93, 0xf0, 0xf2, 0x4f, 0xde, 0xd0, 0x75, 0x49, 0x5d, 0xca, 0x00, 0x6d, 0x99, 0xc2}, // sd nca key source + {0x24, 0x49, 0xb7, 0x22, 0x72, 0x67, 0x03, 0xa8, 0x19, 0x65, 0xe6, 0xe3, 0xea, 0x58, 0x2f, 0xdd, + 0x9a, 0x95, 0x15, 0x17, 0xb1, 0x6e, 0x8f, 0x7f, 0x1f, 0x68, 0x26, 0x31, 0x52, 0xea, 0x29, 0x6a} // sd nca save source +}; + +static const u8 es_keys[3][0x10] = { + {0xdb, 0xa4, 0x51, 0x12, 0x4c, 0xa0, 0xa9, 0x83, 0x68, 0x14, 0xf5, 0xed, 0x95, 0xe3, 0x12, 0x5b}, + {0x46, 0x6e, 0x57, 0xb7, 0x4a, 0x44, 0x7f, 0x02, 0xf3, 0x21, 0xcd, 0xe5, 0x8f, 0x2f, 0x55, 0x35}, + {0x7f, 0x5b, 0xb0, 0x84, 0x7b, 0x25, 0xaa, 0x67, 0xfa, 0xc8, 0x4b, 0xe2, 0x3d, 0x7b, 0x69, 0x03} +}; + +static const u8 ssl_keys[0x10] = { + 0x9a, 0x38, 0x3b, 0xf4, 0x31, 0xd0, 0xbd, 0x81, 0x32, 0x53, 0x4b, 0xa9, 0x64, 0x39, 0x7d, 0xe3}; + static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ @@ -113,66 +142,3 @@ static const u8 bis_key_source[3][0x20] = { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; - -static const u8 fs_hashes_sha256[13][0x20] = { - { // header_kek_source - 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, - 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, - { // header_key_source - 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba, - 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, - { // key_area_key_application_source - 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f, - 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, - { // key_area_key_ocean_source - 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b, - 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, - { // key_area_key_system_source - 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e, - 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, - { // save_mac_kek_source - 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A, - 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, - { // save_mac_key_source - 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, - 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, - { // save_mac_sd_card_kek_source - 0x60, 0x1a, 0x60, 0xbe, 0x13, 0xf6, 0x3e, 0xda, 0xec, 0xcc, 0x96, 0x7f, 0x27, 0xa3, 0xa3, 0x64, - 0x65, 0xcb, 0xe8, 0xf0, 0x29, 0xf0, 0xc4, 0x14, 0xb2, 0x36, 0x6a, 0x8b, 0x8a, 0x0f, 0x13, 0x00}, - { // save_mac_sd_card_key_source - 0xc2, 0x22, 0x0a, 0x38, 0xb6, 0x87, 0x2b, 0x63, 0xee, 0x77, 0xac, 0x8c, 0x28, 0x24, 0x7a, 0x44, - 0x02, 0xe6, 0xdd, 0x85, 0x24, 0x8b, 0x41, 0x9a, 0x6f, 0x9b, 0x17, 0x93, 0xc0, 0x50, 0x3f, 0x21}, - { // sd_card_custom_storage_key_source - 0x6b, 0x8f, 0xd2, 0x6c, 0x76, 0x5b, 0x7c, 0x67, 0x70, 0x0c, 0x68, 0x54, 0x90, 0x8e, 0xbe, 0x88, - 0x45, 0xb0, 0x55, 0xa6, 0xbb, 0xbb, 0xea, 0x0c, 0x06, 0x3a, 0x85, 0x04, 0x12, 0xd4, 0xca, 0x53}, - { // sd_card_kek_source - 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, - 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, - { // sd_card_nca_key_source - 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0, - 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, - { // sd_card_save_key_source - 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A, - 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C} -}; - -static const u8 es_hashes_sha256[3][0x20] = { - { // eticket_rsa_kek - 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73, - 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, - { // eticket_rsa_kekek - 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96, - 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C} -}; - -static const u8 ssl_hashes_sha256[2][0x20] = { - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, - { // ssl_rsa_kek_source_y - 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47, - 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42} -}; \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c index 3d7fd05..6218aaf 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -25,7 +25,7 @@ #include "../hos/pkg2.h" #include "../hos/sept.h" #include -#include +#include #include #include #include @@ -84,14 +84,25 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key); -// nca functions -static void *_nca_process(u32 tweak_ks, u32 crypt_ks, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); -static void _update_ctr(u8 *ctr, u32 ofs); // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); +static inline const u8 *_find_tsec_fw(const u8 *pkg1) { + const u32 tsec_fw_align = 0x100; + const u32 tsec_fw_first_instruction = 0xCF42004D; + + for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + PKG1_MAX_SIZE; pos += tsec_fw_align / sizeof(u32)) + if (*pos == tsec_fw_first_instruction) + return (const u8 *)pos; + + return NULL; +} + +static inline u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { + return 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; +} + void dump_keys() { u8 temp_key[0x10], bis_key[4][0x20] = {0}, @@ -99,14 +110,11 @@ void dump_keys() { device_key_4x[0x10] = {0}, sd_seed[0x10] = {0}, // FS-related keys - fs_keys[13][0x20] = {0}, header_key[0x20] = {0}, save_mac_key[0x10] = {0}, - // other sysmodule sources - es_keys[3][0x10] = {0}, + // other sysmodule keys eticket_rsa_kek[0x10] = {0}, eticket_rsa_kek_personalized[0x10] = {0}, - ssl_keys[0x10] = {0}, ssl_rsa_kek[0x10] = {0}, // keyblob-derived families keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, @@ -147,12 +155,12 @@ void dump_keys() { TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); // Read package1. - u8 *pkg1 = (u8 *)malloc(0x40000); + u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { EPRINTF("Unable to set partition."); goto out_wait; } - if (!emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1)) { + if (!emummc_storage_read(&emmc_storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { EPRINTF("Unable to read pkg1."); goto out_wait; } @@ -162,32 +170,23 @@ void dump_keys() { goto out_wait; } - bool pkg1_not_100 = memcmp(pkg1_id->id, "2016", 4); - - bool found_tsec_fw = false; - for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) { - if (*pos == 0xCF42004D) { - tsec_ctxt.fw = (u8 *)pos; - found_tsec_fw = true; - break; - } - } - if (!found_tsec_fw) { + tsec_ctxt.fw = _find_tsec_fw(pkg1); + if (!tsec_ctxt.fw) { EPRINTF("Unable to locate TSEC firmware."); goto out_wait; } minerva_periodic_training(); - tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); tsec_ctxt.pkg1 = pkg1; - tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; - - u32 MAX_KEY = 6; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) { - MAX_KEY = pkg1_id->kb + 1; + tsec_ctxt.size = _get_tsec_fw_size((tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_OFFSET)); + if (tsec_ctxt.size > PKG1_MAX_SIZE) { + EPRINTF("Unexpected TSEC firmware size."); + goto out_wait; } + u32 max_derivable_key_index = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { @@ -360,12 +359,10 @@ get_tsec: ; key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key */ minerva_periodic_training(); - u32 key_generation = 0; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { - key_generation = fuse_read_odm_keygen_rev(); - if (key_generation) - key_generation--; - } + u32 key_generation = fuse_read_odm_keygen_rev(); + if (key_generation) + key_generation--; + if (_key_exists(device_key)) { if (key_generation) { _get_device_key(8, temp_key, key_generation, device_key_4x, master_key[0]); @@ -384,127 +381,6 @@ get_tsec: ; memcpy(bis_key[3], bis_key[2], 0x20); } - // Dump package2. - u8 *pkg2 = NULL; - pkg2_kip1_info_t *ki = NULL; - - if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { - EPRINTF("Unable to set partition."); - goto out_wait; - } - // Parse eMMC GPT. - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &emmc_storage); - - // Find package2 partition. - emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); - if (!pkg2_part) { - EPRINTF("Unable to locate Package2."); - goto pkg2_done; - } - - // Read in package2 header and get package2 real size. - u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); - u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); - u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; - free(tmp); - - if (pkg2_size > 0x7FC000) { - EPRINTF("Invalid Package2 header."); - goto pkg2_done; - } - // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); - pkg2 = malloc(pkg2_size_aligned); - nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); - - // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. - minerva_periodic_training(); - pkg2_hdr_t *pkg2_hdr; - pkg2_hdr_t hdr; - u32 pkg2_kb; - for (pkg2_kb = 0; pkg2_kb < MAX_KEY; pkg2_kb++) { - se_aes_key_set(8, master_key[pkg2_kb], 0x10); - se_aes_unwrap_key(8, 8, package2_key_source); - memcpy(&hdr, pkg2 + 0x100, sizeof(pkg2_hdr_t)); - se_aes_crypt_ctr(8, &hdr, sizeof(pkg2_hdr_t), &hdr, sizeof(pkg2_hdr_t), &hdr); - if (hdr.magic == PKG2_MAGIC) - break; - } - if (pkg2_kb == MAX_KEY) { - EPRINTF("Unable to derive Package2 key."); - goto pkg2_done; - } else if (pkg2_kb != pkg1_id->kb) - EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb); - - pkg2_hdr = pkg2_decrypt(pkg2); - if (!pkg2_hdr) { - EPRINTF("Unable to decrypt Package2."); - goto pkg2_done; - } - - TPRINTFARGS("%kDecrypt pkg2... ", colors[(color_idx++) % 6]); - - LIST_INIT(kip1_info); - bool new_pkg2; - if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &new_pkg2)) { - EPRINTF("Unable to locate INI1."); - goto pkg2_done; - } - LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) { - if(ki_tmp->kip1->tid == 0x0100000000000000ULL) { - ki = malloc(sizeof(pkg2_kip1_info_t)); - memcpy(ki, ki_tmp, sizeof(pkg2_kip1_info_t)); - break; - } - } - LIST_FOREACH_SAFE(iter, &kip1_info) - free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); - - if (!ki) { - EPRINTF("Unable to parse INI1."); - goto pkg2_done; - } - - pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data - TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]); - - u8 hash_index = 0; - const u8 key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; - - if (!pkg1_not_100) { - // 1.0.0 doesn't have SD keys at all and the first key isn't aligned with the rest - memcpy(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); - hash_index = 1; - } - - u8 temp_hash[0x20]; - for (u32 i = ki->kip1->sections[0].size_comp + pkg1_id->key_info.start_offset; i < ki->size - 0x20; ) { - minerva_periodic_training(); - se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); - if (!memcmp(temp_hash, fs_hashes_sha256[pkg1_id->key_info.hash_order[hash_index]], 0x20)) { - memcpy(fs_keys[pkg1_id->key_info.hash_order[hash_index]], ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); - i += key_lengths[pkg1_id->key_info.hash_order[hash_index]]; - if (hash_index == pkg1_id->key_info.hash_max - 1) { - if (pkg1_id->key_info.hks_offset_is_from_end) - i = ki->size - pkg1_id->key_info.hks_offset; - else - i = ki->size - (ki->kip1->sections[2].size_decomp - pkg1_id->key_info.hks_offset); - } else if (hash_index == pkg1_id->key_info.hash_max) { - break; - } - hash_index++; - } else { - i += pkg1_id->key_info.alignment; - } - } -pkg2_done: - if (ki) { - free(ki); - } - free(pkg2); - u8 *rights_ids = NULL, *titlekeys = NULL; TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); @@ -520,10 +396,10 @@ pkg2_done: se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[FS_SAVE_MAC_KEY_SOURCE]); } - if (_key_exists(master_key[MAX_KEY])) { - MAX_KEY = KB_FIRMWARE_VERSION_MAX + 1; + if (_key_exists(master_key[max_derivable_key_index])) { + max_derivable_key_index = KB_FIRMWARE_VERSION_MAX + 1; } - for (u32 i = 0; i < MAX_KEY; i++) { + for (u32 i = 0; i < max_derivable_key_index; i++) { if (!_key_exists(master_key[i])) continue; if (_key_exists(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE])) { @@ -543,6 +419,25 @@ pkg2_done: goto key_output; } + FILINFO fno; + FIL fp; + save_ctx_t *save_ctx = NULL; + bool save_process_success = false; + u32 read_bytes = 0; + + // derive eticket_rsa_kek and ssl_rsa_kek + if (_key_exists(master_key[0])) { + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); + + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); + } + // Set BIS keys. // PRODINFO/PRODINFOF se_aes_key_set(0, bis_key[0] + 0x00, 0x10); @@ -558,6 +453,14 @@ pkg2_done: se_aes_key_set(8, header_key + 0x00, 0x10); se_aes_key_set(9, header_key + 0x10, 0x10); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { + EPRINTF("Unable to set partition."); + goto out_wait; + } + // Parse eMMC GPT. + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &emmc_storage); + emmc_part_t *system_part = nx_emmc_part_find(&gpt, "SYSTEM"); if (!system_part) { EPRINTF("Unable to locate System partition."); @@ -571,120 +474,6 @@ pkg2_done: goto key_output; } - DIR dir; - FILINFO fno; - FIL fp; - save_ctx_t *save_ctx = NULL; - bool save_process_success = false; - - // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient - u8 *dec_header = (u8*)malloc(0x600); - char path[100] = "bis:/Contents/registered"; - u32 titles_found = 0, read_bytes = 0, title_limit = pkg1_not_100 ? 2 : 1; - u8 *temp_file = NULL; - - if (f_opendir(&dir, path)) { - EPRINTF("Unable to open System:/Contents/registered."); - goto dismount; - } - - gfx_printf("%kSector cache... ", colors[(color_idx++) % 6]); - // prepopulate /Contents/registered in decrypted sector cache - while (!f_readdir(&dir, &fno) && fno.fname[0]) {} - f_closedir(&dir); - TPRINTF(); - - if (pkg1_not_100) { - gfx_printf("%kES & SSL keys...", colors[(color_idx++) % 6]); - } else { - gfx_printf("%kSSL keys... ", colors[(color_idx++) % 6]); - } - - if (f_opendir(&dir, path)) { - EPRINTF("Unable to open System:/Contents/registered."); - goto dismount; - } - - path[24] = '/'; - while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { - minerva_periodic_training(); - memcpy(path + 25, fno.fname, 36); - path[61] = 0; - if (fno.fattrib & AM_DIR) - memcpy(path + 61, "/00", 4); - if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) continue; - if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 0x20, &read_bytes) || read_bytes != 0x20) { - f_close(&fp); - continue; - } - se_aes_xts_crypt_sec(9, 8, 0, 1, dec_header + 0x200, dec_header, 0x20); - // es doesn't contain es key sources on 1.0.0 - if (pkg1_not_100 && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { - u8 hash_order[3] = {0, 1, 2}; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { - hash_order[0] = 1; - hash_order[1] = 0; - } - hash_index = 0; - // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(9, 8, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); - for (u32 i = 0; i <= 0xb0; ) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { - memcpy(es_keys[hash_order[hash_index]], temp_file + i, 0x10); - hash_index++; - if (hash_index == 3) - break; - i += 0x10; - } else { - i++; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { - temp_file = (u8*)_nca_process(9, 8, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); - for (u32 i = 0; i <= 0x60; i++) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { - memcpy(ssl_keys, temp_file + i, 0x10); - // only get ssl_rsa_kek_source_x from SSL on 1.0.0 - // we get it from ES on every other firmware - // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 - if (!pkg1_not_100) { - se_calc_sha256(temp_hash, temp_file + i + 0x10, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[0], 0x10)) - memcpy(es_keys[2], temp_file + i + 0x10, 0x10); - } - break; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } - f_close(&fp); - } - f_closedir(&dir); - free(dec_header); - - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); - } - if (_key_exists(ssl_keys) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); - } - - TPRINTF(); - char private_path[200] = "sd:/"; if (emu_cfg.nintendo_path && (emu_cfg.enabled || !h_cfg.emummc_force_disable)) { strcat(private_path, emu_cfg.nintendo_path); @@ -735,7 +524,7 @@ get_titlekeys: 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; - u32 buf_size = 0x40000; + u32 buf_size = 0x4000; u8 *buffer = (u8 *)MIXD_BUF_ALIGNED; u8 keypair[0x230] = {0}; @@ -824,14 +613,17 @@ get_titlekeys: goto dismount; } - while (br == buf_size && offset < ticket_file.size) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + bool terminator_reached = false; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) break; offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) { + terminator_reached = true; break; + } file_tkey_count++; } } @@ -843,10 +635,9 @@ get_titlekeys: } offset = 0; - br = buf_size; - - while (br == buf_size && offset < ticket_file.size) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + terminator_reached = false; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) break; offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { @@ -861,6 +652,7 @@ get_titlekeys: memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); _titlekey_count++; } else { + terminator_reached = true; break; } } @@ -902,15 +694,17 @@ get_titlekeys: offset = 0; file_tkey_count = 0; - br = buf_size; - while (br == buf_size && offset < ticket_file.size) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + terminator_reached = false; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) break; offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) { + terminator_reached = true; break; + } file_tkey_count++; } } @@ -924,9 +718,9 @@ get_titlekeys: offset = 0; pct = 0; last_pct = 0; - br = buf_size; - while (br == buf_size && offset < ticket_file.size) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + terminator_reached = false; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) break; offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { @@ -950,6 +744,7 @@ get_titlekeys: memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); _titlekey_count++; } else { + terminator_reached = true; break; } } @@ -994,23 +789,23 @@ key_output: ; SAVE_KEY("header_kek_source", fs_keys[FS_HEADER_KEK_SOURCE], 0x10); SAVE_KEY("header_key", header_key, 0x20); SAVE_KEY("header_key_source", fs_keys[FS_HEADER_KEY_SOURCE], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, max_derivable_key_index, 0x10); SAVE_KEY("key_area_key_application_source", fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, max_derivable_key_index, 0x10); SAVE_KEY("key_area_key_ocean_source", fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, max_derivable_key_index, 0x10); SAVE_KEY("key_area_key_system_source", fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE], 0x10); SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_kek", master_kek, 0, max_derivable_key_index, 0x10); SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); - SAVE_KEY_FAMILY("master_key", master_key, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_key", master_key, 0, max_derivable_key_index, 0x10); SAVE_KEY("master_key_source", master_key_source, 0x10); SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("package2_key", package2_key, 0, max_derivable_key_index, 0x10); SAVE_KEY("package2_key_source", package2_key_source, 0x10); SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); @@ -1034,7 +829,7 @@ key_output: ; SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("titlekek", titlekek, 0, max_derivable_key_index, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) @@ -1045,7 +840,7 @@ key_output: ; end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], max_derivable_key_index - 1); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; @@ -1132,67 +927,6 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); } -static void *_nca_process(u32 tweak_ks, u32 crypt_ks, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { - u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; - - u8 *temp_file = (u8*)malloc(0x400), - ctr[0x10] = {0}; - if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400) { - free(temp_file); - return NULL; - } - se_aes_xts_crypt(tweak_ks, crypt_ks, 0, 1, temp_file, temp_file, 0x200, 2); - // both 1.x and 2.x use master_key_00 - temp_file[0x20] -= temp_file[0x20] ? 1 : 0; - // decrypt key area and load decrypted key area key - se_aes_key_set(7, key_area_key[temp_file[7]][temp_file[0x20]], 0x10); - se_aes_crypt_block_ecb(7, 0, temp_file + 0x120, temp_file + 0x120); - se_aes_key_set(6, temp_file + 0x120, 0x10); - for (u32 i = 0; i < 8; i++) - ctr[i] = temp_file[0x347 - i]; - crypt_offset = _read_le_u32(temp_file, 0x40) * 0x200 + _read_le_u32(temp_file, 0x240); - read_size = 0x10; - _nca_fread_ctr(6, fp, temp_file, crypt_offset, read_size, ctr); - num_files = _read_le_u32(temp_file, 4); - string_table_size = _read_le_u32(temp_file, 8); - if (!memcmp(temp_file + 0x10 + num_files * 0x18, "main.npdm", 9)) - crypt_offset += _read_le_u32(temp_file, 0x18); - crypt_offset += 0x10 + num_files * 0x18 + string_table_size; - read_size = 0x40; - _nca_fread_ctr(6, fp, temp_file, crypt_offset, read_size, ctr); - rodata_offset = _read_le_u32(temp_file, 0x20); - - void *buf = malloc(len); - _nca_fread_ctr(6, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr); - free(temp_file); - - return buf; -} - -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr) { - u32 br; - if (f_lseek(fp, offset) || f_read(fp, buffer, len, &br) || br != len) - return 0; - _update_ctr(ctr, offset); - - if (offset % 0x10) { - u8 *temp = (u8*)malloc(ALIGN(br + offset % 0x10, 0x10)); - memcpy(temp + offset % 0x10, buffer, br); - se_aes_crypt_ctr(ks, temp, ALIGN(br + offset % 0x10, 0x10), temp, ALIGN(br + offset % 0x10, 0x10), ctr); - memcpy(buffer, temp + offset % 0x10, br); - free(temp); - return br; - } - se_aes_crypt_ctr(ks, buffer, br, buffer, br, ctr); - return br; -} - -static void _update_ctr(u8 *ctr, u32 ofs) { - ofs >>= 4; - for (u32 i = 0; i < 4; i++, ofs >>= 8) - ctr[0x10-i-1] = (u8)(ofs & 0xff); -} - static bool _test_key_pair(const void *E, const void *D, const void *N) { u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0}; From c4172d77e117c8a424511634bcd1cea4427da22c Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 13 Jul 2020 16:22:36 -0600 Subject: [PATCH 083/166] keys: Improve readability, read keyblobs at once --- bdk/sec/tsec.h | 3 +- source/hos/pkg1.h | 4 ++ source/keys/key_sources.inl | 87 ++++++++++++++++++------------------ source/keys/keys.c | 80 ++++++++++++++++++--------------- source/storage/nx_emmc_bis.h | 3 ++ 5 files changed, 97 insertions(+), 80 deletions(-) diff --git a/bdk/sec/tsec.h b/bdk/sec/tsec.h index 29b9317..274b6e7 100644 --- a/bdk/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -20,7 +20,7 @@ #include -#define TSEC_KEY_DATA_ADDR 0x300 +#define TSEC_KEY_DATA_OFFSET 0x300 typedef struct _tsec_ctxt_t { @@ -43,6 +43,7 @@ typedef struct _tsec_key_data_t u32 blob2_size; u32 blob3_size; u32 blob4_size; + u8 reserved[0x7C]; } tsec_key_data_t; int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index 50b4e91..b488ec0 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -33,6 +33,10 @@ #define FS_SD_NCA_KEY_SOURCE 11 #define FS_SD_SAVE_KEY_SOURCE 12 +#define PKG1_MAX_SIZE 0x40000 +#define PKG1_OFFSET 0x100000 +#define KEYBLOB_OFFSET 0x180000 + typedef struct _key_info_t { u32 start_offset; diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 5d2f824..1bbc040 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -33,7 +33,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 }; -static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = +static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ @@ -70,57 +70,39 @@ static const u8 master_key_source[0x10] = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; static const u8 per_console_key_source[0x10] = { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; -static const u8 per_console_key_source_4x[0x10] = { +static const u8 device_master_key_source_kek_source[0x10] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; +static const u8 mariko_master_kek_source[0x10] = { + 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}; -static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ - {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ - {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ - {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ - {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ - {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ - {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */ -}; - -static const u8 fs_keys[13][0x20] = { - {0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}, // header key source - {0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, - 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}, // encrypted header key - {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // kak appli - {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // kak ocean - {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // kak system - {0xd8, 0x9c, 0x23, 0x6e, 0xc9, 0x12, 0x4e, 0x43, 0xc8, 0x2b, 0x03, 0x87, 0x43, 0xf9, 0xcf, 0x1b}, // save mac kek source - {0xe4, 0xcd, 0x3d, 0x4a, 0xd5, 0x0f, 0x74, 0x28, 0x45, 0xa4, 0x87, 0xe5, 0xa0, 0x63, 0xea, 0x1f}, // save mac key source - {0x04, 0x89, 0xef, 0x5d, 0x32, 0x6e, 0x1a, 0x59, 0xc4, 0xb7, 0xab, 0x8c, 0x36, 0x7a, 0xab, 0x17}, // save mac sd kek source - {0x6f, 0x64, 0x59, 0x47, 0xc5, 0x61, 0x46, 0xf9, 0xff, 0xa0, 0x45, 0xd5, 0x95, 0x33, 0x29, 0x18}, // save mac sd key source - {0x37, 0x0c, 0x34, 0x5e, 0x12, 0xe4, 0xce, 0xfe, 0x21, 0xb5, 0x8e, 0x64, 0xdb, 0x52, 0xaf, 0x35, - 0x4f, 0x2c, 0xa5, 0xa3, 0xfc, 0x99, 0x9a, 0x47, 0xc0, 0x3e, 0xe0, 0x04, 0x48, 0x5b, 0x2f, 0xd0}, // sd custom key source - {0x88, 0x35, 0x8d, 0x9c, 0x62, 0x9b, 0xa1, 0xa0, 0x01, 0x47, 0xdb, 0xe0, 0x62, 0x1b, 0x54, 0x32}, // sd card kek source - {0x58, 0x41, 0xa2, 0x84, 0x93, 0x5b, 0x56, 0x27, 0x8b, 0x8e, 0x1f, 0xc5, 0x18, 0xe9, 0x9f, 0x2b, - 0x67, 0xc7, 0x93, 0xf0, 0xf2, 0x4f, 0xde, 0xd0, 0x75, 0x49, 0x5d, 0xca, 0x00, 0x6d, 0x99, 0xc2}, // sd nca key source - {0x24, 0x49, 0xb7, 0x22, 0x72, 0x67, 0x03, 0xa8, 0x19, 0x65, 0xe6, 0xe3, 0xea, 0x58, 0x2f, 0xdd, - 0x9a, 0x95, 0x15, 0x17, 0xb1, 0x6e, 0x8f, 0x7f, 0x1f, 0x68, 0x26, 0x31, 0x52, 0xea, 0x29, 0x6a} // sd nca save source +static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ + {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */ + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */ + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */ + {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ + {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ }; static const u8 es_keys[3][0x10] = { - {0xdb, 0xa4, 0x51, 0x12, 0x4c, 0xa0, 0xa9, 0x83, 0x68, 0x14, 0xf5, 0xed, 0x95, 0xe3, 0x12, 0x5b}, - {0x46, 0x6e, 0x57, 0xb7, 0x4a, 0x44, 0x7f, 0x02, 0xf3, 0x21, 0xcd, 0xe5, 0x8f, 0x2f, 0x55, 0x35}, - {0x7f, 0x5b, 0xb0, 0x84, 0x7b, 0x25, 0xaa, 0x67, 0xfa, 0xc8, 0x4b, 0xe2, 0x3d, 0x7b, 0x69, 0x03} + {0xdb, 0xa4, 0x51, 0x12, 0x4c, 0xa0, 0xa9, 0x83, 0x68, 0x14, 0xf5, 0xed, 0x95, 0xe3, 0x12, 0x5b}, // eticket_rsa_kek_source + {0x46, 0x6e, 0x57, 0xb7, 0x4a, 0x44, 0x7f, 0x02, 0xf3, 0x21, 0xcd, 0xe5, 0x8f, 0x2f, 0x55, 0x35}, // eticket_rsa_kekek_source + {0x7f, 0x5b, 0xb0, 0x84, 0x7b, 0x25, 0xaa, 0x67, 0xfa, 0xc8, 0x4b, 0xe2, 0x3d, 0x7b, 0x69, 0x03}, // ssl_rsa_kek_source_x }; static const u8 ssl_keys[0x10] = { - 0x9a, 0x38, 0x3b, 0xf4, 0x31, 0xd0, 0xbd, 0x81, 0x32, 0x53, 0x4b, 0xa9, 0x64, 0x39, 0x7d, 0xe3}; + 0x9a, 0x38, 0x3b, 0xf4, 0x31, 0xd0, 0xbd, 0x81, 0x32, 0x53, 0x4b, 0xa9, 0x64, 0x39, 0x7d, 0xe3}; // ssl_rsa_kek_source_y -static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ - {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ - {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ - {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ - {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ - {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */ +static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ + {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */ + {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */ + {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */ + {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ }; @@ -142,3 +124,22 @@ static const u8 bis_key_source[3][0x20] = { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; +static const u8 fs_keys[13][0x20] = { + {0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}, // header key source + {0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, + 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}, // encrypted header key + {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // kak appli + {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // kak ocean + {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // kak system + {0xd8, 0x9c, 0x23, 0x6e, 0xc9, 0x12, 0x4e, 0x43, 0xc8, 0x2b, 0x03, 0x87, 0x43, 0xf9, 0xcf, 0x1b}, // save mac kek source + {0xe4, 0xcd, 0x3d, 0x4a, 0xd5, 0x0f, 0x74, 0x28, 0x45, 0xa4, 0x87, 0xe5, 0xa0, 0x63, 0xea, 0x1f}, // save mac key source + {0x04, 0x89, 0xef, 0x5d, 0x32, 0x6e, 0x1a, 0x59, 0xc4, 0xb7, 0xab, 0x8c, 0x36, 0x7a, 0xab, 0x17}, // save mac sd kek source + {0x6f, 0x64, 0x59, 0x47, 0xc5, 0x61, 0x46, 0xf9, 0xff, 0xa0, 0x45, 0xd5, 0x95, 0x33, 0x29, 0x18}, // save mac sd key source + {0x37, 0x0c, 0x34, 0x5e, 0x12, 0xe4, 0xce, 0xfe, 0x21, 0xb5, 0x8e, 0x64, 0xdb, 0x52, 0xaf, 0x35, + 0x4f, 0x2c, 0xa5, 0xa3, 0xfc, 0x99, 0x9a, 0x47, 0xc0, 0x3e, 0xe0, 0x04, 0x48, 0x5b, 0x2f, 0xd0}, // sd custom key source + {0x88, 0x35, 0x8d, 0x9c, 0x62, 0x9b, 0xa1, 0xa0, 0x01, 0x47, 0xdb, 0xe0, 0x62, 0x1b, 0x54, 0x32}, // sd card kek source + {0x58, 0x41, 0xa2, 0x84, 0x93, 0x5b, 0x56, 0x27, 0x8b, 0x8e, 0x1f, 0xc5, 0x18, 0xe9, 0x9f, 0x2b, + 0x67, 0xc7, 0x93, 0xf0, 0xf2, 0x4f, 0xde, 0xd0, 0x75, 0x49, 0x5d, 0xca, 0x00, 0x6d, 0x99, 0xc2}, // sd nca key source + {0x24, 0x49, 0xb7, 0x22, 0x72, 0x67, 0x03, 0xa8, 0x19, 0x65, 0xe6, 0xe3, 0xea, 0x58, 0x2f, 0xdd, + 0x9a, 0x95, 0x15, 0x17, 0xb1, 0x6e, 0x8f, 0x7f, 0x1f, 0x68, 0x26, 0x31, 0x52, 0xea, 0x29, 0x6a}, // sd nca save source +}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 6218aaf..189722f 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -88,21 +88,23 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const v static bool _test_key_pair(const void *E, const void *D, const void *N); static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); -static inline const u8 *_find_tsec_fw(const u8 *pkg1) { +static inline u8 *_find_tsec_fw(const u8 *pkg1) { const u32 tsec_fw_align = 0x100; const u32 tsec_fw_first_instruction = 0xCF42004D; for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + PKG1_MAX_SIZE; pos += tsec_fw_align / sizeof(u32)) if (*pos == tsec_fw_first_instruction) - return (const u8 *)pos; + return (u8 *)pos; return NULL; } static inline u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { - return 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; + return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; } +#define RELOC_META_OFF 0x7C + void dump_keys() { u8 temp_key[0x10], bis_key[4][0x20] = {0}, @@ -185,7 +187,7 @@ void dump_keys() { goto out_wait; } - u32 max_derivable_key_index = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; + u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { sd_mount(); @@ -198,6 +200,7 @@ void dump_keys() { if (!h_cfg.sept_run) { // bundle lp0 fw for sept instead of loading it from SD as hekate does sdram_lp0_save_params(sdram_get_params_patched()); + FIL fp; if (f_stat("sd:/sept", NULL)) { EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); @@ -211,7 +214,8 @@ void dump_keys() { } } // write self to payload.bin to run again when sept finishes - u32 payload_size = _read_le_u32((u8 *)IPL_LOAD_ADDR, 0x84) - IPL_LOAD_ADDR; + volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); + u32 payload_size = relocator->end - IPL_LOAD_ADDR; if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { EPRINTF("Unable to open /sept/payload.bin to write."); goto out_wait; @@ -269,6 +273,8 @@ get_tsec: ; TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); // Master key derivation + + // on firmware 6.2.0 only, tsec_query delivers the tsec_root_key if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { se_aes_key_set(8, tsec_keys + 0x10, 0x10); // mkek6 = unwrap(mkeks6, tsecroot) se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]); @@ -281,10 +287,10 @@ get_tsec: ; if (_key_exists(master_key[pkg1_id->kb])) { for (u32 i = pkg1_id->kb; i > 0; i--) { se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]); + se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); } se_aes_key_set(8, master_key[0], 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); + se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); if (_key_exists(temp_key)) { EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); memset(master_key, 0, sizeof(master_key)); @@ -294,10 +300,10 @@ get_tsec: ; for (u32 kb = KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { for (u32 i = kb; i > 0; i--) { se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]); + se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); } se_aes_key_set(8, master_key[0], 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); + se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); if (!_key_exists(temp_key)) { break; } @@ -305,19 +311,25 @@ get_tsec: ; memset(master_key[kb], 0, 0x10); } if (_key_exists(temp_key)) { - EPRINTF("Unable to derive master key."); + EPRINTF("Unable to derive master keys via sept."); memset(master_key, 0, sizeof(master_key)); } } } - u8 *keyblob_block = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); + u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); + u8 *current_keyblob = keyblob_block; u8 keyblob_mac[0x10] = {0}; u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; se_aes_key_set(8, tsec_keys, 0x10); se_aes_key_set(9, sbk, 0x10); - for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) { + + if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { + EPRINTF("Unable to read keyblob."); + } + + for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob += NX_EMMC_BLOCKSIZE) { minerva_periodic_training(); se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) @@ -325,26 +337,22 @@ get_tsec: ; se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, 0, device_key_4x, per_console_key_source_4x); + se_aes_crypt_block_ecb(7, 0, device_key_4x, device_master_key_source_kek_source); } // verify keyblob is not corrupt - if (!emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block)) { - EPRINTFARGS("Unable to read keyblob %x.", i); - continue; - } se_aes_key_set(10, keyblob_mac_key[i], 0x10); - se_aes_cmac(10, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); - if (memcmp(keyblob_block, keyblob_mac, 0x10) != 0) { + se_aes_cmac(10, keyblob_mac, 0x10, current_keyblob + 0x10, 0xa0); + if (memcmp(current_keyblob, keyblob_mac, 0x10) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); - gfx_hexdump(i, keyblob_block, 0x10); + gfx_hexdump(i, current_keyblob, 0x10); gfx_hexdump(i, keyblob_mac, 0x10); continue; } // decrypt keyblobs se_aes_key_set(6, keyblob_key[i], 0x10); - se_aes_crypt_ctr(6, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10); + se_aes_crypt_ctr(6, keyblob[i], 0x90, current_keyblob + 0x20, 0x90, current_keyblob + 0x10); memcpy(package1_key[i], keyblob[i] + 0x80, 0x10); memcpy(master_kek[i], keyblob[i], 0x10); @@ -396,10 +404,10 @@ get_tsec: ; se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[FS_SAVE_MAC_KEY_SOURCE]); } - if (_key_exists(master_key[max_derivable_key_index])) { - max_derivable_key_index = KB_FIRMWARE_VERSION_MAX + 1; + if (_key_exists(master_key[derivable_key_count])) { + derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1; } - for (u32 i = 0; i < max_derivable_key_index; i++) { + for (u32 i = 0; i < derivable_key_count; i++) { if (!_key_exists(master_key[i])) continue; if (_key_exists(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE])) { @@ -529,12 +537,12 @@ get_titlekeys: u8 keypair[0x230] = {0}; - if (!emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer)) { + if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, buffer)) { EPRINTF("Unable to read PRODINFO."); goto dismount; } - se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, 1); + se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, NX_EMMC_CALIBRATION_SIZE / 0x4000); nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)buffer; if (cal0->magic != 0x304C4143) { @@ -789,23 +797,23 @@ key_output: ; SAVE_KEY("header_kek_source", fs_keys[FS_HEADER_KEK_SOURCE], 0x10); SAVE_KEY("header_key", header_key, 0x20); SAVE_KEY("header_key_source", fs_keys[FS_HEADER_KEY_SOURCE], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, derivable_key_count, 0x10); SAVE_KEY("key_area_key_application_source", fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, derivable_key_count, 0x10); SAVE_KEY("key_area_key_ocean_source", fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, derivable_key_count, 0x10); SAVE_KEY("key_area_key_system_source", fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE], 0x10); SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("master_kek", master_kek, 0, derivable_key_count, 0x10); SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); - SAVE_KEY_FAMILY("master_key", master_key, 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("master_key", master_key, 0, derivable_key_count, 0x10); SAVE_KEY("master_key_source", master_key_source, 0x10); SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("package2_key", package2_key, 0, derivable_key_count, 0x10); SAVE_KEY("package2_key_source", package2_key_source, 0x10); SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); @@ -829,7 +837,7 @@ key_output: ; SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, 0, max_derivable_key_index, 0x10); + SAVE_KEY_FAMILY("titlekek", titlekek, 0, derivable_key_count, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) @@ -840,7 +848,7 @@ key_output: ; end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], max_derivable_key_index - 1); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; @@ -921,9 +929,9 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo revision -= KB_FIRMWARE_VERSION_400; u8 temp_key[0x10] = {0}; se_aes_key_set(ks, device_key, 0x10); - se_aes_crypt_ecb(ks, 0, temp_key, 0x10, new_device_key_sources[revision], 0x10); + se_aes_crypt_ecb(ks, 0, temp_key, 0x10, device_master_key_source_sources[revision], 0x10); se_aes_key_set(ks, master_key, 0x10); - se_aes_unwrap_key(ks, ks, new_device_keygen_sources[revision]); + se_aes_unwrap_key(ks, ks, device_master_kek_sources[revision]); se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); } diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 09ec063..9e4094f 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -224,6 +224,9 @@ typedef struct _nx_emmc_cal0_t u8 console_6axis_sensor_mount_type; } __attribute__((packed)) nx_emmc_cal0_t; +#define NX_EMMC_CALIBRATION_OFFSET 0x4400 +#define NX_EMMC_CALIBRATION_SIZE 0x8000 + int nx_emmc_bis_read(u32 sector, u32 count, void *buff); int nx_emmc_bis_write(u32 sector, u32 count, void *buff); void nx_emmc_bis_cluster_cache_init(); From bd134cf670822880ac55b3192bfcb949aa176ec7 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 3 Dec 2020 18:16:55 -0700 Subject: [PATCH 084/166] Support firmware 11.0.0, continue refactor --- bdk/memory_map.h | 1 + bdk/sec/se.c | 78 +++++ bdk/sec/se.h | 1 + bdk/utils/types.h | 21 ++ source/gfx/gfx.c | 44 +++ source/gfx/gfx.h | 1 + source/hos/pkg1.c | 87 +---- source/hos/pkg1.h | 31 +- source/keys/key_sources.inl | 73 ++-- source/keys/keys.c | 633 +++++++++++++++-------------------- source/keys/keys.h | 84 +++++ source/storage/nx_emmc_bis.c | 2 +- source/storage/nx_emmc_bis.h | 4 +- 13 files changed, 567 insertions(+), 493 deletions(-) diff --git a/bdk/memory_map.h b/bdk/memory_map.h index 84f4a6d..6a83651 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -60,6 +60,7 @@ // SDMMC DMA buffers 2 #define SDXC_BUF_ALIGNED 0xEF000000 #define MIXD_BUF_ALIGNED 0xF0000000 +#define TITLEKEY_BUF_ADR MIXD_BUF_ALIGNED #define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED #define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 8cd5c2c..7be46c9 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -344,6 +344,11 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s // random calls were derived from Atmosphère's int se_initialize_rng() { + static bool initialized = false; + + if (initialized) + return 1; + u8 *output_buf = (u8 *)malloc(0x10); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); @@ -357,6 +362,8 @@ int se_initialize_rng() int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0); free(output_buf); + if (res) + initialized = true; return res; } @@ -600,3 +607,74 @@ out:; free(opad); return res; } + +// _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) +{ + u8 cur_hash[0x20]; + u8 hash_buf[0xe4]; + + u32 hash_buf_size = seed_size + 4; + memcpy(hash_buf, seed, seed_size); + u32 round_num = 0; + + u8 *p_out = (u8 *)masked; + + while (masked_size) { + u32 cur_size = MIN(masked_size, 0x20); + + for (u32 i = 0; i < 4; i++) + hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; + round_num++; + + se_calc_sha256(cur_hash, hash_buf, hash_buf_size); + + for (unsigned int i = 0; i < cur_size; i++) { + *p_out ^= cur_hash[i]; + p_out++; + } + + masked_size -= cur_size; + } +} + +u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size) +{ + if (dst_size <= 0 || buf_size < 0x43 || label_digest_size != 0x20) + return 0; + + bool is_valid = buf[0] == 0; + + u32 db_len = buf_size - 0x21; + u8 *seed = buf + 1; + u8 *db = seed + 0x20; + _mgf1_xor(seed, 0x20, db, db_len); + _mgf1_xor(db, db_len, seed, 0x20); + + is_valid &= memcmp(label_digest, db, 0x20) ? 0 : 1; + + db += 0x20; + db_len -= 0x20; + + int msg_ofs = 0; + int looking_for_one = 1; + int invalid_db_padding = 0; + int is_zero; + int is_one; + for (int i = 0; i < db_len; ) + { + is_zero = (db[i] == 0); + is_one = (db[i] == 1); + msg_ofs += (looking_for_one & is_one) * (++i); + looking_for_one &= ~is_one; + invalid_db_padding |= (looking_for_one & ~is_zero); + } + + is_valid &= (invalid_db_padding == 0); + + const u32 msg_size = MIN(dst_size, is_valid * (db_len - msg_ofs)); + memcpy(dst, db + msg_ofs, msg_size); + + return msg_size; +} + diff --git a/bdk/sec/se.h b/bdk/sec/se.h index ed4f40f..f10acb3 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -42,5 +42,6 @@ int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, co int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); +u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); #endif diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 62f9eef..9d85ca0 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -19,10 +19,15 @@ #define NULL ((void *)0) +#define ALWAYS_INLINE inline __attribute__((always_inline)) + #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define DIV_ROUND_UP(a, b) ((a + b - 1) / b) + +#define LOG2(n) (32 - __builtin_clz(n) - 1) #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) @@ -91,4 +96,20 @@ typedef struct __attribute__((__packed__)) _reloc_meta_t u32 ep; } reloc_meta_t; +typedef enum +{ + VALIDITY_UNCHECKED = 0, + VALIDITY_INVALID, + VALIDITY_VALID +} validity_t; + +typedef enum +{ + OPEN_MODE_READ = 1, + OPEN_MODE_WRITE = 2, + OPEN_MODE_ALLOW_APPEND = 4, + OPEN_MODE_READ_WRITE = OPEN_MODE_READ | OPEN_MODE_WRITE, + OPEN_MODE_ALL = OPEN_MODE_READ | OPEN_MODE_WRITE | OPEN_MODE_ALLOW_APPEND +} open_mode_t; + #endif diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 3ed440c..70a7292 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -457,6 +457,50 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_con.fntsz = prevFontSize; } +void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len) +{ + if (gfx_con.mute) + return; + + if (memcmp(buf1, buf2, len) == 0) + { + gfx_printf("Diff: No differences found.\n"); + return; + } + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + for(u32 i = 0; i < len; i+=0x10) + { + u32 bytes_left = len - i < 0x10 ? len - i : 0x10; + if (memcmp(buf1 + i, buf2 + i, bytes_left) == 0) + continue; + gfx_printf("Diff 1: %08x: ", base + i); + for (u32 j = 0; j < bytes_left; j++) + { + if (buf1[i+j] != buf2[i+j]) + gfx_con.fgcol = COLOR_ORANGE; + gfx_printf("%02x ", buf1[i+j]); + gfx_con.fgcol = 0xFFCCCCCC; + } + gfx_puts("| "); + gfx_putc('\n'); + gfx_printf("Diff 2: %08x: ", base + i); + for (u32 j = 0; j < bytes_left; j++) + { + if (buf1[i+j] != buf2[i+j]) + gfx_con.fgcol = COLOR_ORANGE; + gfx_printf("%02x ", buf2[i+j]); + gfx_con.fgcol = 0xFFCCCCCC; + } + gfx_puts("| "); + gfx_putc('\n'); + gfx_putc('\n'); + } + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + static int abs(int x) { if (x < 0) diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index ab4ea1e..582cbbb 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -64,6 +64,7 @@ void gfx_putc(char c); void gfx_puts(const char *s); void gfx_printf(const char *fmt, ...); void gfx_hexdump(u32 base, const u8 *buf, u32 len); +void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len); void gfx_set_pixel(u32 x, u32 y, u32 color); void gfx_line(int x0, int y0, int x1, int y1, u32 color); diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 30bb805..8f81334 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -22,78 +22,23 @@ #include "pkg1.h" #include -#define HASH_ORDER_100_100 { \ - FS_KEY_AREA_KEY_APPLI_SOURCE, \ - FS_KEY_AREA_KEY_OCEAN_SOURCE, \ - FS_KEY_AREA_KEY_SYSTE_SOURCE, \ - FS_HEADER_KEK_SOURCE, \ - FS_SAVE_MAC_KEK_SOURCE, \ - FS_SAVE_MAC_KEY_SOURCE, \ - FS_HEADER_KEY_SOURCE \ - } - -#define HASH_ORDER_200_510 { \ - FS_KEY_AREA_KEY_APPLI_SOURCE, \ - FS_KEY_AREA_KEY_OCEAN_SOURCE, \ - FS_KEY_AREA_KEY_SYSTE_SOURCE, \ - FS_HEADER_KEK_SOURCE, \ - FS_SAVE_MAC_KEK_SOURCE, \ - FS_SAVE_MAC_SD_KEK_SOURCE, \ - FS_SD_KEK_SOURCE, \ - FS_SD_SAVE_KEY_SOURCE, \ - FS_SD_NCA_KEY_SOURCE, \ - FS_SAVE_MAC_KEY_SOURCE, \ - FS_SAVE_MAC_SD_KEY_SOURCE, \ - FS_HEADER_KEY_SOURCE \ - } - -#define HASH_ORDER_600_620 { \ - FS_SAVE_MAC_KEY_SOURCE, \ - FS_SAVE_MAC_KEK_SOURCE, \ - FS_SD_KEK_SOURCE, \ - FS_SAVE_MAC_SD_KEK_SOURCE, \ - FS_SAVE_MAC_SD_KEY_SOURCE, \ - FS_KEY_AREA_KEY_APPLI_SOURCE, \ - FS_KEY_AREA_KEY_OCEAN_SOURCE, \ - FS_KEY_AREA_KEY_SYSTE_SOURCE, \ - FS_HEADER_KEK_SOURCE, \ - FS_SD_SAVE_KEY_SOURCE, \ - FS_SD_NCA_KEY_SOURCE, \ - FS_HEADER_KEY_SOURCE \ - } - -#define HASH_ORDER_700_10x { \ - FS_SAVE_MAC_KEY_SOURCE, \ - FS_SAVE_MAC_KEK_SOURCE, \ - FS_SD_KEK_SOURCE, \ - FS_SAVE_MAC_SD_KEK_SOURCE, \ - FS_SAVE_MAC_SD_KEY_SOURCE, \ - FS_KEY_AREA_KEY_APPLI_SOURCE, \ - FS_KEY_AREA_KEY_OCEAN_SOURCE, \ - FS_KEY_AREA_KEY_SYSTE_SOURCE, \ - FS_HEADER_KEK_SOURCE, \ - FS_SD_SAVE_KEY_SOURCE, \ - FS_SD_NCA_KEY_SOURCE, \ - FS_SD_CUSTOM_KEY_SOURCE, \ - FS_HEADER_KEY_SOURCE \ - } - static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0 - { "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0 - { "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0 - { "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2 - { "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.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 - { "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_10x, 0x5563, 0x1d437} }, //7.0.0 - { "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_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 - { "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_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 - { "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+ + { "20161121183008", 0 }, //1.0.0 + { "20170210155124", 0 }, //2.0.0 - 2.3.0 + { "20170519101410", 1 }, //3.0.0 + { "20170710161758", 2 }, //3.0.1 - 3.0.2 + { "20170921172629", 3 }, //4.0.0 - 4.1.0 + { "20180220163747", 4 }, //5.0.0 - 5.1.0 + { "20180802162753", 5 }, //6.0.0 - 6.1.0 + { "20181107105733", 6 }, //6.2.0 + { "20181218175730", 7 }, //7.0.0 + { "20190208150037", 7 }, //7.0.1 + { "20190314172056", 7 }, //8.0.0 - 8.0.1 + { "20190531152432", 8 }, //8.1.0 + { "20190809135709", 9 }, //9.0.0 - 9.0.1 + { "20191021113848", 10}, //9.1.0 + { "20200303104606", 10}, //10.0.0 - 10.2.0 + { "20201030110855", 10}, //11.0.0 { NULL } //End. }; diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index b488ec0..da1df35 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -19,41 +19,14 @@ #include -#define FS_HEADER_KEK_SOURCE 0 -#define FS_HEADER_KEY_SOURCE 1 -#define FS_KEY_AREA_KEY_APPLI_SOURCE 2 -#define FS_KEY_AREA_KEY_OCEAN_SOURCE 3 -#define FS_KEY_AREA_KEY_SYSTE_SOURCE 4 -#define FS_SAVE_MAC_KEK_SOURCE 5 -#define FS_SAVE_MAC_KEY_SOURCE 6 -#define FS_SAVE_MAC_SD_KEK_SOURCE 7 -#define FS_SAVE_MAC_SD_KEY_SOURCE 8 -#define FS_SD_CUSTOM_KEY_SOURCE 9 -#define FS_SD_KEK_SOURCE 10 -#define FS_SD_NCA_KEY_SOURCE 11 -#define FS_SD_SAVE_KEY_SOURCE 12 - -#define PKG1_MAX_SIZE 0x40000 -#define PKG1_OFFSET 0x100000 +#define PKG1_MAX_SIZE 0x40000 +#define PKG1_OFFSET 0x100000 #define KEYBLOB_OFFSET 0x180000 -typedef struct _key_info_t -{ - u32 start_offset; - u32 hks_offset; - bool hks_offset_is_from_end; - u32 alignment; - u32 hash_max; - u8 hash_order[13]; - u32 es_offset; - u32 ssl_offset; -} key_info_t; - typedef struct _pkg1_id_t { const char *id; u32 kb; - key_info_t key_info; } pkg1_id_t; const pkg1_id_t *pkg1_identify(u8 *pkg1); diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 1bbc040..5cb7f08 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -16,6 +16,10 @@ static u8 zeros[0x10] = {0}; +static u8 null_hash[0x20] = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + static const u8 keyblob_key_source[][0x10] = { {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 @@ -33,8 +37,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 }; -static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = -{ +static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ @@ -86,14 +89,17 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ }; -static const u8 es_keys[3][0x10] = { - {0xdb, 0xa4, 0x51, 0x12, 0x4c, 0xa0, 0xa9, 0x83, 0x68, 0x14, 0xf5, 0xed, 0x95, 0xe3, 0x12, 0x5b}, // eticket_rsa_kek_source - {0x46, 0x6e, 0x57, 0xb7, 0x4a, 0x44, 0x7f, 0x02, 0xf3, 0x21, 0xcd, 0xe5, 0x8f, 0x2f, 0x55, 0x35}, // eticket_rsa_kekek_source - {0x7f, 0x5b, 0xb0, 0x84, 0x7b, 0x25, 0xaa, 0x67, 0xfa, 0xc8, 0x4b, 0xe2, 0x3d, 0x7b, 0x69, 0x03}, // ssl_rsa_kek_source_x -}; +// from ES +static const u8 eticket_rsa_kek_source[0x10] = { + 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; +static const u8 eticket_rsa_kekek_source[0x10] = { + 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; -static const u8 ssl_keys[0x10] = { - 0x9a, 0x38, 0x3b, 0xf4, 0x31, 0xd0, 0xbd, 0x81, 0x32, 0x53, 0x4b, 0xa9, 0x64, 0x39, 0x7d, 0xe3}; // ssl_rsa_kek_source_y +// from SSL +static const u8 ssl_rsa_kek_source_x[0x10] = { + 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; +static const u8 ssl_rsa_kek_source_y[0x10] = { + 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ @@ -124,22 +130,35 @@ static const u8 bis_key_source[3][0x20] = { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; -static const u8 fs_keys[13][0x20] = { - {0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}, // header key source - {0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, - 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}, // encrypted header key - {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // kak appli - {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // kak ocean - {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // kak system - {0xd8, 0x9c, 0x23, 0x6e, 0xc9, 0x12, 0x4e, 0x43, 0xc8, 0x2b, 0x03, 0x87, 0x43, 0xf9, 0xcf, 0x1b}, // save mac kek source - {0xe4, 0xcd, 0x3d, 0x4a, 0xd5, 0x0f, 0x74, 0x28, 0x45, 0xa4, 0x87, 0xe5, 0xa0, 0x63, 0xea, 0x1f}, // save mac key source - {0x04, 0x89, 0xef, 0x5d, 0x32, 0x6e, 0x1a, 0x59, 0xc4, 0xb7, 0xab, 0x8c, 0x36, 0x7a, 0xab, 0x17}, // save mac sd kek source - {0x6f, 0x64, 0x59, 0x47, 0xc5, 0x61, 0x46, 0xf9, 0xff, 0xa0, 0x45, 0xd5, 0x95, 0x33, 0x29, 0x18}, // save mac sd key source - {0x37, 0x0c, 0x34, 0x5e, 0x12, 0xe4, 0xce, 0xfe, 0x21, 0xb5, 0x8e, 0x64, 0xdb, 0x52, 0xaf, 0x35, - 0x4f, 0x2c, 0xa5, 0xa3, 0xfc, 0x99, 0x9a, 0x47, 0xc0, 0x3e, 0xe0, 0x04, 0x48, 0x5b, 0x2f, 0xd0}, // sd custom key source - {0x88, 0x35, 0x8d, 0x9c, 0x62, 0x9b, 0xa1, 0xa0, 0x01, 0x47, 0xdb, 0xe0, 0x62, 0x1b, 0x54, 0x32}, // sd card kek source - {0x58, 0x41, 0xa2, 0x84, 0x93, 0x5b, 0x56, 0x27, 0x8b, 0x8e, 0x1f, 0xc5, 0x18, 0xe9, 0x9f, 0x2b, - 0x67, 0xc7, 0x93, 0xf0, 0xf2, 0x4f, 0xde, 0xd0, 0x75, 0x49, 0x5d, 0xca, 0x00, 0x6d, 0x99, 0xc2}, // sd nca key source - {0x24, 0x49, 0xb7, 0x22, 0x72, 0x67, 0x03, 0xa8, 0x19, 0x65, 0xe6, 0xe3, 0xea, 0x58, 0x2f, 0xdd, - 0x9a, 0x95, 0x15, 0x17, 0xb1, 0x6e, 0x8f, 0x7f, 0x1f, 0x68, 0x26, 0x31, 0x52, 0xea, 0x29, 0x6a}, // sd nca save source +static const u8 header_kek_source[0x10] = { + 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}; +static const u8 header_key_source[0x20] = { + 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, + 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}; +static const u8 key_area_key_sources[3][0x10] = { + { + 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application + { + 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean + { + 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system }; +static const u8 save_mac_kek_source[0x10] = { + 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; +static const u8 save_mac_key_source[0x10] = { + 0XE4, 0XCD, 0X3D, 0X4A, 0XD5, 0X0F, 0X74, 0X28, 0X45, 0XA4, 0X87, 0XE5, 0XA0, 0X63, 0XEA, 0X1F}; +static const u8 save_mac_sd_card_kek_source[0x10] = { + 0X04, 0X89, 0XEF, 0X5D, 0X32, 0X6E, 0X1A, 0X59, 0XC4, 0XB7, 0XAB, 0X8C, 0X36, 0X7A, 0XAB, 0X17}; +static const u8 save_mac_sd_card_key_source[0x10] = { + 0X6F, 0X64, 0X59, 0X47, 0XC5, 0X61, 0X46, 0XF9, 0XFF, 0XA0, 0X45, 0XD5, 0X95, 0X33, 0X29, 0X18}; +static const u8 sd_card_custom_storage_key_source[0x20] = { + 0X37, 0X0C, 0X34, 0X5E, 0X12, 0XE4, 0XCE, 0XFE, 0X21, 0XB5, 0X8E, 0X64, 0XDB, 0X52, 0XAF, 0X35, + 0X4F, 0X2C, 0XA5, 0XA3, 0XFC, 0X99, 0X9A, 0X47, 0XC0, 0X3E, 0XE0, 0X04, 0X48, 0X5B, 0X2F, 0XD0}; +static const u8 sd_card_kek_source[0x10] = { + 0X88, 0X35, 0X8D, 0X9C, 0X62, 0X9B, 0XA1, 0XA0, 0X01, 0X47, 0XDB, 0XE0, 0X62, 0X1B, 0X54, 0X32}; +static const u8 sd_card_nca_key_source[0x20] = { + 0X58, 0X41, 0XA2, 0X84, 0X93, 0X5B, 0X56, 0X27, 0X8B, 0X8E, 0X1F, 0XC5, 0X18, 0XE9, 0X9F, 0X2B, + 0X67, 0XC7, 0X93, 0XF0, 0XF2, 0X4F, 0XDE, 0XD0, 0X75, 0X49, 0X5D, 0XCA, 0X00, 0X6D, 0X99, 0XC2}; +static const u8 sd_card_save_key_source[0x20] = { + 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, + 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 189722f..a33a260 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -56,28 +56,20 @@ static u32 _key_count = 0, _titlekey_count = 0; static u32 start_time, end_time; u32 color_idx = 0; -#define TPRINTF(text) \ - end_time = get_tmr_us(); \ - gfx_printf(text" done in %d us\n", end_time - start_time); \ - start_time = get_tmr_us(); \ - minerva_periodic_training() - -#define TPRINTFARGS(text, args...) \ - end_time = get_tmr_us(); \ - gfx_printf(text" done in %d us\n", args, end_time - start_time); \ - start_time = get_tmr_us(); \ - minerva_periodic_training() - -#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) -#define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) - -static inline u32 _read_le_u32(const void *buffer, u32 offset) { +static ALWAYS_INLINE u32 _read_le_u32(const void *buffer, u32 offset) { return (*(u8*)(buffer + offset + 0) ) | (*(u8*)(buffer + offset + 1) << 0x08) | (*(u8*)(buffer + offset + 2) << 0x10) | (*(u8*)(buffer + offset + 3) << 0x18); } +static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { + return (*(u8*)(buffer + offset + 3) ) | + (*(u8*)(buffer + offset + 2) << 0x08) | + (*(u8*)(buffer + offset + 1) << 0x10) | + (*(u8*)(buffer + offset + 0) << 0x18); +} + // key functions static int _key_exists(const void *data) { return memcmp(data, zeros, 0x10) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); @@ -86,9 +78,8 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, con static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key); // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); -static inline u8 *_find_tsec_fw(const u8 *pkg1) { +static ALWAYS_INLINE u8 *_find_tsec_fw(const u8 *pkg1) { const u32 tsec_fw_align = 0x100; const u32 tsec_fw_first_instruction = 0xCF42004D; @@ -99,10 +90,137 @@ static inline u8 *_find_tsec_fw(const u8 *pkg1) { return NULL; } -static inline u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { +static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; } +static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { + FIL fp; + u64 br = buf_size; + u64 offset = 0; + u32 file_tkey_count = 0; + u32 save_x = gfx_con.x, save_y = gfx_con.y; + bool is_personalized = rsa_keypair != NULL; + u32 start_titlekey_count = _titlekey_count; + char titlekey_save_path[32] = "bis:/save/80000000000000E1"; + + if (is_personalized) { + titlekey_save_path[25] = '2'; + gfx_printf("\n%kPersonalized... ", colors[color_idx % 6]); + } else { + gfx_printf("\n%kCommon... ", colors[color_idx % 6]); + } + + if (f_open(&fp, titlekey_save_path, FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open e1 save. Skipping."); + return false; + } + + save_ctx_t *save_ctx = calloc(1, sizeof(save_ctx_t)); + save_init(save_ctx, &fp, save_mac_key, 0); + + bool save_process_success = save_process(save_ctx); + TPRINTF("\n Save process..."); + + if (!save_process_success) { + EPRINTF("Failed to process es save."); + f_close(&fp); + save_free_contexts(save_ctx); + free(save_ctx); + return false; + } + + char ticket_bin_path[0x40] = "/ticket.bin"; + char ticket_list_bin_path[0x40] = "/ticket_list.bin"; + save_data_file_ctx_t ticket_file; + + if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { + EPRINTF("Unable to locate ticket_list.bin in save."); + f_close(&fp); + save_free_contexts(save_ctx); + free(save_ctx); + return false; + } + + bool terminator_reached = false; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) + break; + offset += br; + minerva_periodic_training(); + ticket_record_t *curr_ticket_record = (ticket_record_t *)titlekey_buffer->read_buffer; + for (u32 i = 0; i < buf_size; i += sizeof(ticket_record_t), curr_ticket_record++) { + if (curr_ticket_record->rights_id[0] == 0xFF) { + terminator_reached = true; + break; + } + file_tkey_count++; + } + } + TPRINTF(" Count keys..."); + + if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { + EPRINTF("Unable to locate ticket.bin in save."); + f_close(&fp); + save_free_contexts(save_ctx); + free(save_ctx); + return false; + } + + const u32 ticket_sig_type_rsa2048_sha256 = 0x10004; + + offset = 0; + terminator_reached = false; + u32 pct = 0, last_pct = 0; + while (offset < ticket_file.size && !terminator_reached) { + if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) + break; + offset += br; + ticket_t *curr_ticket = (ticket_t *)titlekey_buffer->read_buffer; + for (u32 j = 0; j < buf_size; j += sizeof(ticket_t), curr_ticket++) { + minerva_periodic_training(); + pct = (_titlekey_count - start_titlekey_count) * 100 / file_tkey_count; + if (pct > last_pct && pct <= 100) { + last_pct = pct; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + } + if (curr_ticket->signature_type != ticket_sig_type_rsa2048_sha256) { + terminator_reached = true; + break; + } + if (is_personalized) { + se_rsa_exp_mod(0, curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block), curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block)); + if (se_rsa_oaep_decode( + curr_ticket->titlekey_block, sizeof(titlekey_buffer->titlekeys[0]), + null_hash, sizeof(null_hash), + curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block) + ) != sizeof(titlekey_buffer->titlekeys[0]) + ) + continue; + } + memcpy(titlekey_buffer->rights_ids[_titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); + memcpy(titlekey_buffer->titlekeys[_titlekey_count], curr_ticket->titlekey_block, sizeof(titlekey_buffer->titlekeys[0])); + _titlekey_count++; + } + } + tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); + f_close(&fp); + save_free_contexts(save_ctx); + free(save_ctx); + + gfx_con_setpos(0, save_y); + + if (is_personalized) { + TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); + } else { + TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); + } + + gfx_printf("\n\n\n"); + + return true; +} + #define RELOC_META_OFF 0x7C void dump_keys() { @@ -119,7 +237,6 @@ void dump_keys() { eticket_rsa_kek_personalized[0x10] = {0}, ssl_rsa_kek[0x10] = {0}, // keyblob-derived families - keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, @@ -130,6 +247,8 @@ void dump_keys() { package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; + keyblob_t keyblob[KB_FIRMWARE_VERSION_600+1] = {0}; + sd_mount(); display_backlight_brightness(h_cfg.backlight, 1000); @@ -318,22 +437,22 @@ get_tsec: ; } u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); - u8 *current_keyblob = keyblob_block; + encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u8 keyblob_mac[0x10] = {0}; u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; - se_aes_key_set(8, tsec_keys, 0x10); - se_aes_key_set(9, sbk, 0x10); + se_aes_key_set(8, tsec_keys, sizeof(tsec_keys) / 2); + se_aes_key_set(9, sbk, sizeof(sbk)); if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblob."); } - for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob += NX_EMMC_BLOCKSIZE) { + for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) - se_aes_key_set(7, keyblob_key[i], 0x10); + se_aes_key_set(7, keyblob_key[i], sizeof(keyblob_key[i])); se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) @@ -341,22 +460,20 @@ get_tsec: ; } // verify keyblob is not corrupt - se_aes_key_set(10, keyblob_mac_key[i], 0x10); - se_aes_cmac(10, keyblob_mac, 0x10, current_keyblob + 0x10, 0xa0); - if (memcmp(current_keyblob, keyblob_mac, 0x10) != 0) { + se_aes_key_set(10, keyblob_mac_key[i], sizeof(keyblob_mac_key[i])); + se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); + if (memcmp(current_keyblob, keyblob_mac, sizeof(keyblob_mac)) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); - gfx_hexdump(i, current_keyblob, 0x10); - gfx_hexdump(i, keyblob_mac, 0x10); continue; } // decrypt keyblobs - se_aes_key_set(6, keyblob_key[i], 0x10); - se_aes_crypt_ctr(6, keyblob[i], 0x90, current_keyblob + 0x20, 0x90, current_keyblob + 0x10); + se_aes_key_set(6, keyblob_key[i], sizeof(keyblob_key[i])); + se_aes_crypt_ctr(6, &keyblob[i], sizeof(keyblob_t), ¤t_keyblob->key_data, sizeof(keyblob_t), current_keyblob->iv); - memcpy(package1_key[i], keyblob[i] + 0x80, 0x10); - memcpy(master_kek[i], keyblob[i], 0x10); - se_aes_key_set(7, master_kek[i], 0x10); + memcpy(package1_key[i], keyblob[i].package1_key, sizeof(package1_key[i])); + memcpy(master_kek[i], keyblob[i].master_kek, sizeof(master_kek[i])); + se_aes_key_set(7, master_kek[i], sizeof(master_kek[i])); se_aes_crypt_block_ecb(7, 0, master_key[i], master_key_source); } free(keyblob_block); @@ -389,19 +506,17 @@ get_tsec: ; memcpy(bis_key[3], bis_key[2], 0x20); } - u8 *rights_ids = NULL, *titlekeys = NULL; - TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); - if (_key_exists(fs_keys[FS_HEADER_KEK_SOURCE]) && _key_exists(fs_keys[FS_HEADER_KEY_SOURCE]) && _key_exists(master_key[0])) { - _generate_kek(8, fs_keys[FS_HEADER_KEK_SOURCE], master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[FS_HEADER_KEY_SOURCE] + 0x00); - se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[FS_HEADER_KEY_SOURCE] + 0x10); + if (_key_exists(master_key[0])) { + _generate_kek(8, header_kek_source, master_key[0], aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, header_key + 0x00, header_key_source + 0x00); + se_aes_crypt_block_ecb(8, 0, header_key + 0x10, header_key_source + 0x10); } - if (_key_exists(fs_keys[FS_SAVE_MAC_KEK_SOURCE]) && _key_exists(fs_keys[FS_SAVE_MAC_KEY_SOURCE]) && _key_exists(device_key)) { - _generate_kek(8, fs_keys[FS_SAVE_MAC_KEK_SOURCE], device_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[FS_SAVE_MAC_KEY_SOURCE]); + if (_key_exists(device_key)) { + _generate_kek(8, save_mac_kek_source, device_key, aes_kek_generation_source, NULL); + se_aes_crypt_block_ecb(8, 0, save_mac_key, save_mac_key_source); } if (_key_exists(master_key[derivable_key_count])) { @@ -410,11 +525,9 @@ get_tsec: ; for (u32 i = 0; i < derivable_key_count; i++) { if (!_key_exists(master_key[i])) continue; - if (_key_exists(fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE]) && _key_exists(fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE])) { - for (u32 j = 0; j < 3; j++) { - _generate_kek(8, fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE + j], master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); - } + for (u32 j = 0; j < 3; j++) { + _generate_kek(8, key_area_key_sources[j], master_key[i], aes_kek_generation_source, NULL); + se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); } se_aes_key_set(8, master_key[i], 0x10); se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source); @@ -429,21 +542,19 @@ get_tsec: ; FILINFO fno; FIL fp; - save_ctx_t *save_ctx = NULL; - bool save_process_success = false; u32 read_bytes = 0; // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(master_key[0])) { for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); + _generate_kek(7, eticket_rsa_kekek_source, master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, eticket_rsa_kek_source); for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); + _generate_kek(7, ssl_rsa_kek_source_x, master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_rsa_kek_source_y); } // Set BIS keys. @@ -511,8 +622,8 @@ get_tsec: ; for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; - if (!memcmp(temp_key, read_buf, 0x10)) { - memcpy(sd_seed, read_buf + 0x10, 0x10); + if (!memcmp(temp_key, read_buf, sizeof(temp_key))) { + memcpy(sd_seed, read_buf + 0x10, sizeof(sd_seed)); break; } } @@ -524,35 +635,28 @@ get_titlekeys: if (!_key_exists(eticket_rsa_kek)) goto dismount; - gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); - u32 save_x = gfx_con.x, save_y = gfx_con.y; - gfx_printf("\n%kCommon... ", colors[color_idx % 6]); - - u8 null_hash[0x20] = { - 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, - 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); u32 buf_size = 0x4000; - u8 *buffer = (u8 *)MIXD_BUF_ALIGNED; + rsa_keypair_t rsa_keypair = {0}; - u8 keypair[0x230] = {0}; + titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; - if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, buffer)) { + if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { EPRINTF("Unable to read PRODINFO."); goto dismount; } - se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, NX_EMMC_CALIBRATION_SIZE / 0x4000); + se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)buffer; + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; if (cal0->magic != 0x304C4143) { - EPRINTF("CAL0 magic not found. Check BIS key 0."); + EPRINTF("Invalid CAL0 magic. Check BIS key 0."); goto dismount; } - u32 keypair_generation = cal0->ext_ecc_rsa2048_eticket_key_ver; - if (cal0->version <= 8) - keypair_generation = 0; // settings zeroes this out below cal version 9 + // settings sysmodule manually zeroes this out below cal version 9 + u32 keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; if (keypair_generation) { keypair_generation--; @@ -560,216 +664,35 @@ get_titlekeys: temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; u8 temp_device_key[0x10] = {0}; _get_device_key(7, temp_device_key, keypair_generation, device_key_4x, master_key[0]); - _generate_kek(7, es_keys[1], temp_device_key, temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek_personalized, es_keys[0]); - memcpy(temp_key, eticket_rsa_kek_personalized, 0x10); + _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek_personalized, eticket_rsa_kek_source); + memcpy(temp_key, eticket_rsa_kek_personalized, sizeof(temp_key)); } else { - memcpy(temp_key, eticket_rsa_kek, 0x10); + memcpy(temp_key, eticket_rsa_kek, sizeof(temp_key)); } - se_aes_key_set(6, temp_key, 0x10); - se_aes_crypt_ctr(6, keypair, 0x230, cal0->ext_ecc_rsa2048_eticket_key + 0x10, 0x230, cal0->ext_ecc_rsa2048_eticket_key); + se_aes_key_set(6, temp_key, sizeof(temp_key)); + se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), cal0->ext_ecc_rsa2048_eticket_key, sizeof(cal0->ext_ecc_rsa2048_eticket_key), cal0->ext_ecc_rsa2048_eticket_key_iv); - u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; - - // Check public exponent is 0x10001 big endian - if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { + // Check public exponent is 65537 big endian + if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { EPRINTF("Invalid public exponent."); goto dismount; } - if (!_test_key_pair(E, D, N)) { + if (!_test_key_pair(rsa_keypair.public_exponent, rsa_keypair.private_exponent, rsa_keypair.modulus)) { EPRINTF("Invalid keypair. Check eticket_rsa_kek."); goto dismount; } - se_rsa_key_set(0, N, 0x100, D, 0x100); + se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); - u64 br = buf_size; - u32 file_tkey_count = 0; - u64 offset = 0; - rights_ids = (u8 *)(MIXD_BUF_ALIGNED + 0x40000); - titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000); - save_ctx = calloc(1, sizeof(save_ctx_t)); - u8 M[0x100]; - if (f_open(&fp, "bis:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open e1 save. Skipping."); - goto dismount; - } + _get_titlekeys_from_save(buf_size, save_mac_key, titlekey_buffer, NULL); + _get_titlekeys_from_save(buf_size, save_mac_key, titlekey_buffer, &rsa_keypair); - u32 pct = 0, last_pct = 0; - - save_ctx->file = &fp; - save_ctx->action = 0; - memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - - save_process_success = save_process(save_ctx); - - if (!save_process_success) { - EPRINTF("Failed to process e1 save."); - f_close(&fp); - goto dismount; - } - - char ticket_bin_path[0x40] = "/ticket.bin"; - char ticket_list_bin_path[0x40] = "/ticket_list.bin"; - save_data_file_ctx_t ticket_file; - - if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { - EPRINTF("Unable to locate ticket_list.bin in e1."); - f_close(&fp); - goto dismount; - } - - bool terminator_reached = false; - while (offset < ticket_file.size && !terminator_reached) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) - break; - offset += br; - minerva_periodic_training(); - for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) { - terminator_reached = true; - break; - } - file_tkey_count++; - } - } - - if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { - EPRINTF("Unable to locate ticket.bin in e1 save."); - f_close(&fp); - goto dismount; - } - - offset = 0; - terminator_reached = false; - while (offset < ticket_file.size && !terminator_reached) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) - break; - offset += br; - for (u32 j = 0; j < buf_size; j += 0x400) { - pct = _titlekey_count * 100 / file_tkey_count; - if (pct > last_pct && pct <= 100) { - last_pct = pct; - tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); - } - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); - _titlekey_count++; - } else { - terminator_reached = true; - break; - } - } - } - tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); - f_close(&fp); - save_free_contexts(save_ctx); - save_process_success = false; - memset(save_ctx, 0, sizeof(save_ctx_t)); - - gfx_con_setpos(0, save_y); - TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); - save_x = gfx_con.x + 16 * 17; - save_y = gfx_con.y; - gfx_printf("\n%kPersonalized... ", colors[color_idx % 6]); - - u32 common_titlekey_count = _titlekey_count; - if (f_open(&fp, "bis:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open e2 save. Skipping."); - goto dismount; - } - - save_ctx->file = &fp; - save_ctx->action = 0; - memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - - save_process_success = save_process(save_ctx); - if (!save_process_success) { - EPRINTF("Failed to process e2 save."); - f_close(&fp); - goto dismount; - } - - if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { - EPRINTF("Unable to locate ticket_list.bin in e2 save."); - f_close(&fp); - goto dismount; - } - - offset = 0; - file_tkey_count = 0; - terminator_reached = false; - while (offset < ticket_file.size && !terminator_reached) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) - break; - offset += br; - minerva_periodic_training(); - for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) { - terminator_reached = true; - break; - } - file_tkey_count++; - } - } - - if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { - EPRINTF("Unable to locate ticket.bin in e2 save."); - f_close(&fp); - goto dismount; - } - - offset = 0; - pct = 0; - last_pct = 0; - terminator_reached = false; - while (offset < ticket_file.size && !terminator_reached) { - if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0 || br != buf_size) - break; - offset += br; - for (u32 j = 0; j < buf_size; j += 0x400) { - pct = (_titlekey_count - common_titlekey_count) * 100 / file_tkey_count; - if (pct > last_pct && pct <= 100) { - last_pct = pct; - tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); - } - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - - u8 *titlekey_block = buffer + j + 0x180; - se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); - u8 *salt = M + 1; - u8 *db = M + 0x21; - _mgf1_xor(salt, 0x20, db, 0xdf); - _mgf1_xor(db, 0xdf, salt, 0x20); - if (memcmp(db, null_hash, 0x20) != 0) - continue; - memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); - _titlekey_count++; - } else { - terminator_reached = true; - break; - } - } - } - tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); - f_close(&fp); - - gfx_con_setpos(0, save_y); - TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); dismount: ; - if (save_process_success) - save_free_contexts(save_ctx); - - if (save_ctx) - free(save_ctx); f_mount(NULL, "bis:", 1); nx_emmc_gpt_free(&gpt); @@ -780,70 +703,76 @@ key_output: ; EPRINTF("Unable to mount SD."); goto free_buffers; } - u32 text_buffer_size = MAX(_titlekey_count * 68 + 1, 0x4000); + + typedef struct { + char rights_id[0x20]; + char equals[3]; + char titlekey[0x20]; + char newline[1]; + } titlekey_text_buffer_t; + + u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, 0x4000); text_buffer = (char *)calloc(1, text_buffer_size); - SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); - SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); - SAVE_KEY("bis_kek_source", bis_kek_source, 0x10); - SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20); - SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20); - SAVE_KEY("device_key", device_key, 0x10); - SAVE_KEY("device_key_4x", device_key_4x, 0x10); - SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); - SAVE_KEY("eticket_rsa_kek_personalized", eticket_rsa_kek_personalized, 0x10); - SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); - SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10); - SAVE_KEY("header_kek_source", fs_keys[FS_HEADER_KEK_SOURCE], 0x10); - SAVE_KEY("header_key", header_key, 0x20); - SAVE_KEY("header_key_source", fs_keys[FS_HEADER_KEY_SOURCE], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, derivable_key_count, 0x10); - SAVE_KEY("key_area_key_application_source", fs_keys[FS_KEY_AREA_KEY_APPLI_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, derivable_key_count, 0x10); - SAVE_KEY("key_area_key_ocean_source", fs_keys[FS_KEY_AREA_KEY_OCEAN_SOURCE], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, derivable_key_count, 0x10); - SAVE_KEY("key_area_key_system_source", fs_keys[FS_KEY_AREA_KEY_SYSTE_SOURCE], 0x10); - SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); - SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); - SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, 0, derivable_key_count, 0x10); - SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); - SAVE_KEY_FAMILY("master_key", master_key, 0, derivable_key_count, 0x10); - SAVE_KEY("master_key_source", master_key_source, 0x10); - SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, 0, derivable_key_count, 0x10); - SAVE_KEY("package2_key_source", package2_key_source, 0x10); - SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); - SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); + SAVE_KEY(aes_kek_generation_source); + SAVE_KEY(aes_key_generation_source); + SAVE_KEY(bis_kek_source); + SAVE_KEY_FAMILY(bis_key, 0); + SAVE_KEY_FAMILY(bis_key_source, 0); + SAVE_KEY(device_key); + SAVE_KEY(device_key_4x); + SAVE_KEY(eticket_rsa_kek); + SAVE_KEY(eticket_rsa_kek_personalized); + SAVE_KEY(eticket_rsa_kek_source); + SAVE_KEY(eticket_rsa_kekek_source); + SAVE_KEY(header_kek_source); + SAVE_KEY(header_key); + SAVE_KEY(header_key_source); + SAVE_KEY_FAMILY_VAR(key_area_key_application, key_area_key[0], 0); + SAVE_KEY_VAR(key_area_key_application_source, key_area_key_sources[0]); + SAVE_KEY_FAMILY_VAR(key_area_key_ocean, key_area_key[1], 0); + SAVE_KEY_VAR(key_area_key_ocean_source, key_area_key_sources[1]); + SAVE_KEY_FAMILY_VAR(key_area_key_system, key_area_key[2], 0); + SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); + SAVE_KEY_FAMILY(keyblob, 0); + SAVE_KEY_FAMILY(keyblob_key, 0); + SAVE_KEY_FAMILY(keyblob_key_source, 0); + SAVE_KEY_FAMILY(keyblob_mac_key, 0); + SAVE_KEY(keyblob_mac_key_source); + SAVE_KEY_FAMILY(master_kek, 0); + SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); + SAVE_KEY_FAMILY(master_key, 0); + SAVE_KEY(master_key_source); + SAVE_KEY_FAMILY(package1_key, 0); + SAVE_KEY_FAMILY(package2_key, 0); + SAVE_KEY(package2_key_source); + SAVE_KEY(per_console_key_source); + SAVE_KEY(retail_specific_aes_key_source); for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - SAVE_KEY("rsa_oaep_kek_generation_source", temp_key, 0x10); + SAVE_KEY_VAR(rsa_oaep_kek_generation_source, temp_key); for (u32 i = 0; i < 0x10; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - SAVE_KEY("rsa_private_kek_generation_source", temp_key, 0x10); - SAVE_KEY("save_mac_kek_source", fs_keys[FS_SAVE_MAC_KEK_SOURCE], 0x10); - SAVE_KEY("save_mac_key", save_mac_key, 0x10); - SAVE_KEY("save_mac_key_source", fs_keys[FS_SAVE_MAC_KEY_SOURCE], 0x10); - SAVE_KEY("save_mac_sd_card_kek_source", fs_keys[FS_SAVE_MAC_SD_KEK_SOURCE], 0x10); - SAVE_KEY("save_mac_sd_card_key_source", fs_keys[FS_SAVE_MAC_SD_KEY_SOURCE], 0x10); - SAVE_KEY("sd_card_custom_storage_key_source", fs_keys[FS_SD_CUSTOM_KEY_SOURCE], 0x20); - SAVE_KEY("sd_card_kek_source", fs_keys[FS_SD_KEK_SOURCE], 0x10); - SAVE_KEY("sd_card_nca_key_source", fs_keys[FS_SD_NCA_KEY_SOURCE], 0x20); - SAVE_KEY("sd_card_save_key_source", fs_keys[FS_SD_SAVE_KEY_SOURCE], 0x20); - SAVE_KEY("sd_seed", sd_seed, 0x10); - SAVE_KEY("secure_boot_key", sbk, 0x10); - SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); - SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); - SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, 0, derivable_key_count, 0x10); - SAVE_KEY("titlekek_source", titlekek_source, 0x10); - SAVE_KEY("tsec_key", tsec_keys, 0x10); + SAVE_KEY_VAR(rsa_private_kek_generation_source, temp_key); + SAVE_KEY(save_mac_kek_source); + SAVE_KEY(save_mac_key); + SAVE_KEY(save_mac_key_source); + SAVE_KEY(save_mac_sd_card_kek_source); + SAVE_KEY(save_mac_sd_card_key_source); + SAVE_KEY(sd_card_custom_storage_key_source); + SAVE_KEY(sd_card_kek_source); + SAVE_KEY(sd_card_nca_key_source); + SAVE_KEY(sd_card_save_key_source); + SAVE_KEY(sd_seed); + SAVE_KEY_VAR(secure_boot_key, sbk); + SAVE_KEY(ssl_rsa_kek); + SAVE_KEY(ssl_rsa_kek_source_x); + SAVE_KEY(ssl_rsa_kek_source_y); + SAVE_KEY_FAMILY(titlekek, 0); + SAVE_KEY(titlekek_source); + _save_key("tsec_key", tsec_keys, 0x10, text_buffer); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10); - - //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; + _save_key("tsec_root_key", tsec_keys + 0x10, 0x10, text_buffer); end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); @@ -864,13 +793,16 @@ key_output: ; if (_titlekey_count == 0) goto free_buffers; memset(text_buffer, 0, text_buffer_size); + + titlekey_text_buffer_t *titlekey_text = (titlekey_text_buffer_t *)text_buffer; + for (u32 i = 0; i < _titlekey_count; i++) { for (u32 j = 0; j < 0x10; j++) - sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]); - sprintf(&text_buffer[i * 68 + 0x20], " = "); + sprintf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); + sprintf(titlekey_text[i].equals, " = "); for (u32 j = 0; j < 0x10; j++) - sprintf(&text_buffer[i * 68 + 0x23 + j * 2], "%02x", titlekeys[i * 0x10 + j]); - sprintf(&text_buffer[i * 68 + 0x43], "\n"); + sprintf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); + sprintf(titlekey_text[i].newline, "\n"); } sprintf(&keyfile_path[11], "title.keys"); if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { @@ -935,44 +867,17 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); } -static bool _test_key_pair(const void *E, const void *D, const void *N) { - u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0}; +static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { + u8 plaintext[0x100] = {0}, ciphertext[0x100] = {0}, work[0x100] = {0}; // 0xCAFEBABE - X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe; - se_rsa_key_set(0, N, 0x100, D, 0x100); - se_rsa_exp_mod(0, Y, 0x100, X, 0x100); - se_rsa_key_set(0, N, 0x100, E, 4); - se_rsa_exp_mod(0, Z, 0x100, Y, 0x100); + plaintext[0xfc] = 0xca; plaintext[0xfd] = 0xfe; plaintext[0xfe] = 0xba; plaintext[0xff] = 0xbe; - return !memcmp(X, Z, 0x100); -} - -// _mgf1_xor() was derived from Atmosphère's calculate_mgf1_and_xor -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { - u8 cur_hash[0x20]; - u8 hash_buf[0xe4]; - - u32 hash_buf_size = seed_size + 4; - memcpy(hash_buf, seed, seed_size); - u32 round_num = 0; - - u8 *p_out = (u8 *)masked; - - while (masked_size) { - u32 cur_size = MIN(masked_size, 0x20); - - for (u32 i = 0; i < 4; i++) - hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; - round_num++; - - se_calc_sha256(cur_hash, hash_buf, hash_buf_size); - - for (unsigned int i = 0; i < cur_size; i++) { - *p_out ^= cur_hash[i]; - p_out++; - } - - masked_size -= cur_size; - } + se_rsa_key_set(0, modulus, 0x100, private_exponent, 0x100); + se_rsa_exp_mod(0, ciphertext, 0x100, plaintext, 0x100); + + se_rsa_key_set(0, modulus, 0x100, public_exponent, 4); + se_rsa_exp_mod(0, work, 0x100, ciphertext, 0x100); + + return !memcmp(plaintext, work, 0x100); } diff --git a/source/keys/keys.h b/source/keys/keys.h index a0f7afd..ae6ead4 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -17,6 +17,90 @@ #ifndef _KEYS_H_ #define _KEYS_H_ +#include + +// only tickets of type Rsa2048Sha256 are expected +typedef struct { + u32 signature_type; // always 0x10004 + u8 signature[0x100]; + u8 sig_padding[0x3C]; + char issuer[0x40]; + u8 titlekey_block[0x100]; + u8 format_version; + u8 titlekey_type; + u16 ticket_version; + u8 license_type; + u8 common_key_id; + u16 property_mask; + u64 reserved; + u64 ticket_id; + u64 device_id; + u8 rights_id[0x10]; + u32 account_id; + u32 sect_total_size; + u32 sect_hdr_offset; + u16 sect_hdr_count; + u16 sect_hdr_entry_size; + u8 padding[0x140]; +} ticket_t; + +typedef struct { + u8 rights_id[0x10]; + u64 ticket_id; + u32 account_id; + u16 property_mask; + u16 reserved; +} ticket_record_t; + +typedef struct { + u8 read_buffer[0x40000]; + u8 rights_ids[0x40000 / 0x10][0x10]; + u8 titlekeys[0x40000 / 0x10][0x10]; +} titlekey_buffer_t; + +typedef struct { + u8 private_exponent[0x100]; + u8 modulus[0x100]; + u8 public_exponent[4]; + u8 reserved[0x14]; + u64 device_id; + u8 gmac[0x10]; +} rsa_keypair_t; + +typedef struct { + u8 master_kek[0x10]; + u8 data[0x70]; + u8 package1_key[0x10]; +} keyblob_t; + +typedef struct { + u8 cmac[0x10]; + u8 iv[0x10]; + keyblob_t key_data; + u8 unused[0x150]; +} encrypted_keyblob_t; + +#define TPRINTF(text) \ + end_time = get_tmr_us(); \ + gfx_printf(text" done in %d us\n", end_time - start_time); \ + start_time = get_tmr_us(); \ + minerva_periodic_training() + +#define TPRINTFARGS(text, args...) \ + end_time = get_tmr_us(); \ + gfx_printf(text" done in %d us\n", args, end_time - start_time); \ + start_time = get_tmr_us(); \ + minerva_periodic_training() + +// save key wrapper +#define SAVE_KEY(name) _save_key(#name, name, sizeof(name), text_buffer) +// save key with different name than variable +#define SAVE_KEY_VAR(name, varname) _save_key(#name, varname, sizeof(varname), text_buffer) +// save key family wrapper +#define SAVE_KEY_FAMILY(name, start) _save_key_family(#name, name, start, sizeof(name) / sizeof(name[0]), sizeof(name[0]), text_buffer) +// save key family with different name than variable +#define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, sizeof(varname) / sizeof(varname[0]), sizeof(varname[0]), text_buffer) + void dump_keys(); #endif diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 22e90c3..243a3ee 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -24,12 +24,12 @@ #include #include #include "../storage/nx_emmc.h" +#include "nx_emmc_bis.h" #include #include #define MAX_CLUSTER_CACHE_ENTRIES 32768 #define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF -#define XTS_CLUSTER_SIZE 0x4000 #define SECTORS_PER_CLUSTER 0x20 typedef struct diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 9e4094f..3a6aeca 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -163,7 +163,8 @@ typedef struct _nx_emmc_cal0_t u8 crc16_pad36[0x10]; u8 ext_ecc_b233_eticket_key[0x50]; u8 crc16_pad37[0x10]; - u8 ext_ecc_rsa2048_eticket_key[0x240]; + u8 ext_ecc_rsa2048_eticket_key_iv[0x10]; + u8 ext_ecc_rsa2048_eticket_key[0x230]; u32 ext_ecc_rsa2048_eticket_key_ver; u8 crc16_pad38[0xC]; u8 ext_ssl_key[0x130]; @@ -226,6 +227,7 @@ typedef struct _nx_emmc_cal0_t #define NX_EMMC_CALIBRATION_OFFSET 0x4400 #define NX_EMMC_CALIBRATION_SIZE 0x8000 +#define XTS_CLUSTER_SIZE 0x4000 int nx_emmc_bis_read(u32 sector, u32 count, void *buff); int nx_emmc_bis_write(u32 sector, u32 count, void *buff); From 04378b322dbebcdc0e8c44d946cbe5ffe16c99fc Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 3 Dec 2020 18:43:16 -0700 Subject: [PATCH 085/166] Huge savedata driver refactor --- bdk/libs/nx_savedata/allocation_table.c | 281 ++++++ bdk/libs/nx_savedata/allocation_table.h | 171 ++++ .../nx_savedata/allocation_table_iterator.c | 111 +++ .../nx_savedata/allocation_table_iterator.h | 56 ++ .../nx_savedata/allocation_table_storage.c | 158 ++++ .../nx_savedata/allocation_table_storage.h | 60 ++ bdk/libs/nx_savedata/cached_storage.c | 227 +++++ bdk/libs/nx_savedata/cached_storage.h | 68 ++ bdk/libs/nx_savedata/directory_entry.h | 60 ++ bdk/libs/nx_savedata/duplex_storage.c | 108 +++ bdk/libs/nx_savedata/duplex_storage.h | 76 ++ bdk/libs/nx_savedata/fs_int64.h | 40 + bdk/libs/nx_savedata/header.h | 237 +++++ .../nx_savedata/hierarchical_duplex_storage.c | 120 +++ .../nx_savedata/hierarchical_duplex_storage.h | 61 ++ ...rarchical_integrity_verification_storage.c | 174 ++++ ...rarchical_integrity_verification_storage.h | 110 +++ .../hierarchical_save_file_table.c | 483 ++++++++++ .../hierarchical_save_file_table.h | 59 ++ .../integrity_verification_storage.c | 155 ++++ .../integrity_verification_storage.h | 60 ++ bdk/libs/nx_savedata/journal_map.c | 63 ++ bdk/libs/nx_savedata/journal_map.h | 84 ++ bdk/libs/nx_savedata/journal_storage.c | 92 ++ bdk/libs/nx_savedata/journal_storage.h | 69 ++ bdk/libs/nx_savedata/path_parser.c | 84 ++ bdk/libs/nx_savedata/path_parser.h | 59 ++ bdk/libs/nx_savedata/remap_storage.c | 160 ++++ bdk/libs/nx_savedata/remap_storage.h | 104 +++ bdk/libs/nx_savedata/save.c | 306 +++++++ bdk/libs/nx_savedata/save.h | 154 ++++ bdk/libs/nx_savedata/save_data_directory.c | 89 ++ bdk/libs/nx_savedata/save_data_directory.h | 56 ++ bdk/libs/nx_savedata/save_data_file.c | 132 +++ bdk/libs/nx_savedata/save_data_file.h | 62 ++ .../nx_savedata/save_data_file_system_core.c | 142 +++ .../nx_savedata/save_data_file_system_core.h | 79 ++ bdk/libs/nx_savedata/save_fs_entry.h | 66 ++ bdk/libs/nx_savedata/save_fs_list.c | 300 +++++++ bdk/libs/nx_savedata/save_fs_list.h | 99 +++ bdk/libs/nx_savedata/storage.c | 241 +++++ bdk/libs/nx_savedata/storage.h | 169 ++++ source/keys/save.c | 829 ------------------ source/keys/save.h | 526 ----------- 44 files changed, 5485 insertions(+), 1355 deletions(-) create mode 100644 bdk/libs/nx_savedata/allocation_table.c create mode 100644 bdk/libs/nx_savedata/allocation_table.h create mode 100644 bdk/libs/nx_savedata/allocation_table_iterator.c create mode 100644 bdk/libs/nx_savedata/allocation_table_iterator.h create mode 100644 bdk/libs/nx_savedata/allocation_table_storage.c create mode 100644 bdk/libs/nx_savedata/allocation_table_storage.h create mode 100644 bdk/libs/nx_savedata/cached_storage.c create mode 100644 bdk/libs/nx_savedata/cached_storage.h create mode 100644 bdk/libs/nx_savedata/directory_entry.h create mode 100644 bdk/libs/nx_savedata/duplex_storage.c create mode 100644 bdk/libs/nx_savedata/duplex_storage.h create mode 100644 bdk/libs/nx_savedata/fs_int64.h create mode 100644 bdk/libs/nx_savedata/header.h create mode 100644 bdk/libs/nx_savedata/hierarchical_duplex_storage.c create mode 100644 bdk/libs/nx_savedata/hierarchical_duplex_storage.h create mode 100644 bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c create mode 100644 bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.h create mode 100644 bdk/libs/nx_savedata/hierarchical_save_file_table.c create mode 100644 bdk/libs/nx_savedata/hierarchical_save_file_table.h create mode 100644 bdk/libs/nx_savedata/integrity_verification_storage.c create mode 100644 bdk/libs/nx_savedata/integrity_verification_storage.h create mode 100644 bdk/libs/nx_savedata/journal_map.c create mode 100644 bdk/libs/nx_savedata/journal_map.h create mode 100644 bdk/libs/nx_savedata/journal_storage.c create mode 100644 bdk/libs/nx_savedata/journal_storage.h create mode 100644 bdk/libs/nx_savedata/path_parser.c create mode 100644 bdk/libs/nx_savedata/path_parser.h create mode 100644 bdk/libs/nx_savedata/remap_storage.c create mode 100644 bdk/libs/nx_savedata/remap_storage.h create mode 100644 bdk/libs/nx_savedata/save.c create mode 100644 bdk/libs/nx_savedata/save.h create mode 100644 bdk/libs/nx_savedata/save_data_directory.c create mode 100644 bdk/libs/nx_savedata/save_data_directory.h create mode 100644 bdk/libs/nx_savedata/save_data_file.c create mode 100644 bdk/libs/nx_savedata/save_data_file.h create mode 100644 bdk/libs/nx_savedata/save_data_file_system_core.c create mode 100644 bdk/libs/nx_savedata/save_data_file_system_core.h create mode 100644 bdk/libs/nx_savedata/save_fs_entry.h create mode 100644 bdk/libs/nx_savedata/save_fs_list.c create mode 100644 bdk/libs/nx_savedata/save_fs_list.h create mode 100644 bdk/libs/nx_savedata/storage.c create mode 100644 bdk/libs/nx_savedata/storage.h delete mode 100644 source/keys/save.c delete mode 100644 source/keys/save.h diff --git a/bdk/libs/nx_savedata/allocation_table.c b/bdk/libs/nx_savedata/allocation_table.c new file mode 100644 index 0000000..b6a0a52 --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "allocation_table.h" +#include "allocation_table_iterator.h" + +#include + +void save_allocation_table_init(allocation_table_ctx_t *ctx, void *storage, allocation_table_header_t *header) { + ctx->base_storage = storage; + ctx->header = header; + ctx->free_list_entry_index = 0; +} + +void save_allocation_table_set_free_list_entry_index(allocation_table_ctx_t *ctx, uint32_t head_block_index) { + allocation_table_entry_t free_list = {0, head_block_index}; + save_allocation_table_write_entry(ctx, ctx->free_list_entry_index, &free_list); +} + +void save_allocation_table_set_free_list_block_index(allocation_table_ctx_t *ctx, uint32_t head_block_index) { + save_allocation_table_set_free_list_entry_index(ctx, allocation_table_block_to_entry_index(head_block_index)); +} + +uint32_t save_allocation_table_get_list_tail(allocation_table_ctx_t *ctx, uint32_t entry_index) { + uint32_t tail_index = entry_index; + uint32_t table_size = ctx->header->fat_storage_info.count; + uint32_t nodes_traversed = 0; + + allocation_table_entry_t *entry = save_allocation_table_read_entry(ctx, entry_index); + + while (!allocation_table_is_list_end(entry)) { + nodes_traversed++; + tail_index = allocation_table_get_next(entry); + entry = save_allocation_table_read_entry(ctx, tail_index); + if (nodes_traversed > table_size) { + EPRINTF("Cycle detected in allocation table!"); + return 0xFFFFFFFF; + } + } + + return tail_index; +} + +bool save_allocation_table_split(allocation_table_ctx_t *ctx, uint32_t segment_block_index, uint32_t first_sub_segment_length) { + uint32_t seg_a_index = allocation_table_block_to_entry_index(segment_block_index); + + allocation_table_entry_t *seg_a = save_allocation_table_read_entry(ctx, seg_a_index); + + if (!allocation_table_is_multi_block_segment(seg_a)) { + EPRINTF("Cannot split a single-entry segment!"); + return false; + } + + allocation_table_entry_t *seg_a_range = save_allocation_table_read_entry(ctx, seg_a_index + 1); + uint32_t original_length = allocation_table_get_next(seg_a_range) - allocation_table_get_prev(seg_a_range) + 1; + + if (first_sub_segment_length >= original_length) { + EPRINTFARGS("Requested sub-segment length (%x) must\n be less than the full segment length (%x)!", first_sub_segment_length, original_length); + return false; + } + + uint32_t seg_b_index = seg_a_index + first_sub_segment_length; + uint32_t seg_a_length = first_sub_segment_length; + uint32_t seg_b_length = original_length - seg_a_length; + + allocation_table_entry_t seg_b = {seg_a_index, allocation_table_get_next(seg_a)}; + allocation_table_set_next(seg_a, seg_b_index); + + if (!allocation_table_is_list_end(&seg_b)) { + allocation_table_entry_t *seg_c = save_allocation_table_read_entry(ctx, allocation_table_get_next(&seg_b)); + allocation_table_set_prev(seg_c, seg_b_index); + } + + if (seg_b_length > 1) { + allocation_table_make_multi_block_segment(&seg_b); + allocation_table_entry_t seg_b_range; + allocation_table_set_range(&seg_b_range, seg_b_index, seg_b_index + seg_b_length - 1); + save_allocation_table_write_entry(ctx, seg_b_index + 1, &seg_b_range); + save_allocation_table_write_entry(ctx, seg_b_index + seg_b_length - 1, &seg_b_range); + } + + save_allocation_table_write_entry(ctx, seg_b_index, &seg_b); + + if (seg_a_length == 1) { + allocation_table_make_single_block_segment(seg_a); + } else { + allocation_table_set_range(seg_a_range, seg_a_index, seg_a_index + seg_a_length - 1); + save_allocation_table_write_entry(ctx, seg_a_index + seg_a_length - 1, seg_a_range); + } + + return true; +} + +uint32_t save_allocation_table_trim(allocation_table_ctx_t *ctx, uint32_t list_head_block_index, uint32_t new_list_length) { + uint32_t blocks_remaining = new_list_length; + uint32_t next_entry = allocation_table_block_to_entry_index(list_head_block_index); + uint32_t list_a_index = 0xFFFFFFFF; + uint32_t list_b_index = 0xFFFFFFFF; + + while (blocks_remaining > 0) { + if (next_entry == 0) + return 0xFFFFFFFF; + + uint32_t current_entry_index = next_entry; + + allocation_table_entry_t entry; + uint32_t segment_length = save_allocation_table_read_entry_with_length(ctx, allocation_table_entry_index_to_block(current_entry_index), &entry); + if (segment_length == 0) { + EPRINTF("Invalid entry detected in allocation table!"); + return 0xFFFFFFFF; + } + + next_entry = allocation_table_block_to_entry_index(entry.next); + + if (segment_length == blocks_remaining) { + list_a_index = current_entry_index; + list_b_index = next_entry; + } else if (segment_length > blocks_remaining) { + if (!save_allocation_table_split(ctx, allocation_table_entry_index_to_block(current_entry_index), blocks_remaining)) + return 0xFFFFFFFF; + list_a_index = current_entry_index; + list_b_index = current_entry_index + blocks_remaining; + segment_length = blocks_remaining; + } + + blocks_remaining -= segment_length; + } + + if (list_a_index == 0xFFFFFFFF || list_b_index == 0xFFFFFFFF) + return 0xFFFFFFFF; + + allocation_table_entry_t *list_a_node = save_allocation_table_read_entry(ctx, list_a_index); + allocation_table_entry_t *list_b_node = save_allocation_table_read_entry(ctx, list_b_index); + + allocation_table_set_next(list_a_node, 0); + allocation_table_make_list_start(list_b_node); + + return allocation_table_entry_index_to_block(list_b_index); +} + +bool save_allocation_table_join(allocation_table_ctx_t *ctx, uint32_t front_list_block_index, uint32_t back_list_block_index) { + uint32_t front_entry_index = allocation_table_block_to_entry_index(front_list_block_index); + uint32_t back_entry_index = allocation_table_block_to_entry_index(back_list_block_index); + + uint32_t front_tail_index = save_allocation_table_get_list_tail(ctx, front_entry_index); + if (front_tail_index == 0xFFFFFFFF) + return false; + + allocation_table_entry_t *front_tail = save_allocation_table_read_entry(ctx, front_tail_index); + allocation_table_entry_t *back_head = save_allocation_table_read_entry(ctx, back_entry_index); + + allocation_table_set_next(front_tail, back_entry_index); + allocation_table_set_prev(back_head, front_tail_index); + + return true; +} + +uint32_t save_allocation_table_allocate(allocation_table_ctx_t *ctx, uint32_t block_count) { + uint32_t free_list = save_allocation_table_get_free_list_block_index(ctx); + uint32_t new_free_list = save_allocation_table_trim(ctx, free_list, block_count); + if (new_free_list == 0xFFFFFFFF) + return 0xFFFFFFFF; + + save_allocation_table_set_free_list_block_index(ctx, new_free_list); + + return free_list; +} + +bool save_allocation_table_free(allocation_table_ctx_t *ctx, uint32_t list_block_index) { + uint32_t list_entry_index = allocation_table_block_to_entry_index(list_block_index); + allocation_table_entry_t *list_entry = save_allocation_table_read_entry(ctx, list_entry_index); + + if (!allocation_table_is_list_start(list_entry)) { + EPRINTF("The block to free must be the start of a list!"); + return false; + } + + uint32_t free_list_index = save_allocation_table_get_free_list_entry_index(ctx); + + if (free_list_index == 0) { + save_allocation_table_set_free_list_entry_index(ctx, list_entry_index); + return true; + } + + save_allocation_table_join(ctx, list_block_index, allocation_table_entry_index_to_block(free_list_index)); + save_allocation_table_set_free_list_block_index(ctx, list_block_index); + + return true; +} + +uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, uint32_t block_index, allocation_table_entry_t *entry) { + uint32_t length; + uint32_t entry_index = allocation_table_block_to_entry_index(block_index); + + allocation_table_entry_t *entries = save_allocation_table_read_entry(ctx, entry_index); + if (allocation_table_is_single_block_segment(&entries[0])) { + length = 1; + if (allocation_table_is_range_entry(&entries[0])) { + EPRINTF("Invalid range entry in allocation table!"); + return 0; + } + } else { + length = entries[1].next - entry_index + 1; + } + + if (allocation_table_is_list_end(&entries[0])) { + entry->next = 0xFFFFFFFF; + } else { + entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0])); + } + + if (allocation_table_is_list_start(&entries[0])) { + entry->prev = 0xFFFFFFFF; + } else { + entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0])); + } + + return length; +} + +uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) { + allocation_table_entry_t entry = {0, block_index}; + uint32_t total_length = 0; + uint32_t table_size = ctx->header->fat_storage_info.count; + uint32_t nodes_iterated = 0; + + while (entry.next != 0xFFFFFFFF) { + uint32_t length = save_allocation_table_read_entry_with_length(ctx, entry.next, &entry); + if (length == 0) { + EPRINTF("Invalid entry detected in allocation table!"); + return 0; + } + total_length += length; + nodes_iterated++; + if (nodes_iterated > table_size) { + EPRINTF("Cycle detected in allocation table!"); + return 0; + } + } + return total_length; +} + +uint32_t save_allocation_table_get_free_list_length(allocation_table_ctx_t *ctx) { + uint32_t free_list_start = save_allocation_table_get_free_list_block_index(ctx); + + if (free_list_start == 0xFFFFFFFF) + return 0; + + return save_allocation_table_get_list_length(ctx, free_list_start); +} diff --git a/bdk/libs/nx_savedata/allocation_table.h b/bdk/libs/nx_savedata/allocation_table.h new file mode 100644 index 0000000..97b3a85 --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _ALLOCATION_TABLE_H_ +#define _ALLOCATION_TABLE_H_ + +#include "storage.h" + +#include +#include +#include + +#define SAVE_FAT_ENTRY_SIZE 8 + +typedef struct { + uint64_t offset; + uint32_t count; + uint32_t _0xC; +} storage_info_t; + +typedef struct { + uint64_t block_size; + storage_info_t fat_storage_info; + storage_info_t data_storage_info; + uint32_t directory_table_block; + uint32_t file_table_block; +} allocation_table_header_t; + +static_assert(sizeof(allocation_table_header_t) == 0x30, "Allocation table header size is wrong!"); + +typedef struct { + uint32_t prev; + uint32_t next; +} allocation_table_entry_t; + +typedef struct { + uint32_t free_list_entry_index; + void *base_storage; + allocation_table_header_t *header; +} allocation_table_ctx_t; + +static ALWAYS_INLINE uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) { + return entry_index - 1; +} + +static ALWAYS_INLINE uint32_t allocation_table_block_to_entry_index(uint32_t block_index) { + return block_index + 1; +} + +static ALWAYS_INLINE int allocation_table_get_prev(allocation_table_entry_t *entry) { + return entry->prev & 0x7FFFFFFF; +} + +static ALWAYS_INLINE int allocation_table_get_next(allocation_table_entry_t *entry) { + return entry->next & 0x7FFFFFFF; +} + +static ALWAYS_INLINE int allocation_table_is_list_start(allocation_table_entry_t *entry) { + return entry->prev == 0x80000000; +} + +static ALWAYS_INLINE int allocation_table_is_list_end(allocation_table_entry_t *entry) { + return (entry->next & 0x7FFFFFFF) == 0; +} + +static ALWAYS_INLINE bool allocation_table_is_multi_block_segment(allocation_table_entry_t *entry) { + return entry->next & 0x80000000; +} + +static ALWAYS_INLINE void allocation_table_make_multi_block_segment(allocation_table_entry_t *entry) { + entry->next |= 0x80000000; +} + +static ALWAYS_INLINE void allocation_table_make_single_block_segment(allocation_table_entry_t *entry) { + entry->next &= 0x7FFFFFFF; +} + +static ALWAYS_INLINE bool allocation_table_is_single_block_segment(allocation_table_entry_t *entry) { + return (entry->next & 0x80000000) == 0; +} + +static ALWAYS_INLINE void allocation_table_make_list_start(allocation_table_entry_t *entry) { + entry->prev = 0x80000000; +} + +static ALWAYS_INLINE bool allocation_table_is_range_entry(allocation_table_entry_t *entry) { + return (entry->prev & 0x80000000) == 0x80000000 && entry->prev != 0x80000000; +} + +static ALWAYS_INLINE void allocation_table_make_range_entry(allocation_table_entry_t *entry) { + entry->prev |= 0x80000000; +} + +static ALWAYS_INLINE void allocation_table_set_next(allocation_table_entry_t *entry, int val) { + entry->next = (entry->next & 0x80000000) | val; +} + +static ALWAYS_INLINE void allocation_table_set_prev(allocation_table_entry_t *entry, int val) { + entry->prev = val; +} + +static ALWAYS_INLINE void allocation_table_set_range(allocation_table_entry_t *entry, int start_index, int end_index) { + entry->next = end_index; + entry->prev = start_index; + allocation_table_make_range_entry(entry); +} + +static ALWAYS_INLINE uint64_t allocation_table_query_size(uint32_t block_count) { + return SAVE_FAT_ENTRY_SIZE * allocation_table_block_to_entry_index(block_count); +} + +static ALWAYS_INLINE allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { + return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE); +} + +static ALWAYS_INLINE void save_allocation_table_write_entry(allocation_table_ctx_t *ctx, uint32_t entry_index, allocation_table_entry_t *entry) { + memcpy((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE, entry, SAVE_FAT_ENTRY_SIZE); +} + +static ALWAYS_INLINE uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) { + return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index)); +} + +static ALWAYS_INLINE uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) { + return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); +} + +void save_allocation_table_init(allocation_table_ctx_t *ctx, void *storage, allocation_table_header_t *header); +void save_allocation_table_set_free_list_entry_index(allocation_table_ctx_t *ctx, uint32_t head_block_index); +void save_allocation_table_set_free_list_block_index(allocation_table_ctx_t *ctx, uint32_t head_block_index); +bool save_allocation_table_split(allocation_table_ctx_t *ctx, uint32_t segment_block_index, uint32_t first_sub_segment_length); +uint32_t save_allocation_table_trim(allocation_table_ctx_t *ctx, uint32_t list_head_block_index, uint32_t new_list_length); +bool save_allocation_table_join(allocation_table_ctx_t *ctx, uint32_t front_list_block_index, uint32_t back_list_block_index); +uint32_t save_allocation_table_allocate(allocation_table_ctx_t *ctx, uint32_t block_count); +bool save_allocation_table_free(allocation_table_ctx_t *ctx, uint32_t list_block_index); +uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, uint32_t block_index, allocation_table_entry_t *entry); +uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index); +uint32_t save_allocation_table_get_free_list_length(allocation_table_ctx_t *ctx); + +#endif diff --git a/bdk/libs/nx_savedata/allocation_table_iterator.c b/bdk/libs/nx_savedata/allocation_table_iterator.c new file mode 100644 index 0000000..957e17d --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table_iterator.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "allocation_table_iterator.h" + +#include + +bool save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) { + ctx->fat = table; + ctx->physical_block = initial_block; + ctx->virtual_block = 0; + + allocation_table_entry_t entry; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, initial_block, &entry); + if (ctx->current_segment_size == 0) { + EPRINTF("Invalid entry detected in allocation table!"); + return false; + } + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + if (ctx->prev_block != 0xFFFFFFFF) { + EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!", initial_block); + return false; + } + return true; +} + +bool save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) { + if (ctx->next_block == 0xFFFFFFFF) + return false; + + ctx->virtual_block += ctx->current_segment_size; + ctx->physical_block = ctx->next_block; + + allocation_table_entry_t entry; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, ctx->next_block, &entry); + if (ctx->current_segment_size == 0) { + EPRINTF("Invalid entry detected in allocation table!"); + return false; + } + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + return true; +} + +bool save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) { + if (ctx->prev_block == 0xFFFFFFFF) + return false; + + ctx->physical_block = ctx->prev_block; + + allocation_table_entry_t entry; + ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, ctx->prev_block, &entry); + if (ctx->current_segment_size == 0) { + EPRINTF("Invalid entry detected in allocation table!"); + return false; + } + ctx->next_block = entry.next; + ctx->prev_block = entry.prev; + + ctx->virtual_block -= ctx->current_segment_size; + + return true; +} + +bool save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) { + for ( ; ; ) { + if (block < ctx->virtual_block) { + if (!save_allocation_table_iterator_move_prev(ctx)) + return false; + } else if (block >= ctx->virtual_block + ctx->current_segment_size) { + if (!save_allocation_table_iterator_move_next(ctx)) + return false; + } else { + return true; + } + } +} diff --git a/bdk/libs/nx_savedata/allocation_table_iterator.h b/bdk/libs/nx_savedata/allocation_table_iterator.h new file mode 100644 index 0000000..8c5ea74 --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table_iterator.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _ALLOCATION_TABLE_ITER_H_ +#define _ALLOCATION_TABLE_ITER_H_ + +#include "allocation_table.h" + +#include + +typedef struct { + allocation_table_ctx_t *fat; + uint32_t virtual_block; + uint32_t physical_block; + uint32_t current_segment_size; + uint32_t next_block; + uint32_t prev_block; +} allocation_table_iterator_ctx_t; + +bool save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block); +bool save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx); +bool save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx); +bool save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block); + +#endif diff --git a/bdk/libs/nx_savedata/allocation_table_storage.c b/bdk/libs/nx_savedata/allocation_table_storage.c new file mode 100644 index 0000000..43cea04 --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table_storage.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "allocation_table_storage.h" + +#include "allocation_table_iterator.h" + +#include + +void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) { + ctx->base_storage = data; + ctx->block_size = block_size; + ctx->fat = table; + ctx->initial_block = initial_block; + ctx->_length = initial_block == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(table, initial_block) * block_size; +} + +uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + allocation_table_iterator_ctx_t iterator; + if (!save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block)) + return 0; + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + if (!save_allocation_table_iterator_seek(&iterator, block_num)) { + EPRINTFARGS("Invalid allocation table offset: %x", (uint32_t)offset); + return 0; + } + + uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size); + uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos; + + uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos; + uint32_t bytes_to_read = MIN(remaining, remaining_in_segment); + + if (substorage_read(ctx->base_storage, (uint8_t *)buffer + out_pos, physical_offset, bytes_to_read) != bytes_to_read) + return 0; + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + allocation_table_iterator_ctx_t iterator; + if (!save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block)) + return 0; + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + if (!save_allocation_table_iterator_seek(&iterator, block_num)) { + EPRINTFARGS("Invalid allocation table offset: %x", (uint32_t)offset); + return 0; + } + + uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size); + uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos; + + uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos; + uint32_t bytes_to_write = MIN(remaining, remaining_in_segment); + + + if (substorage_write(ctx->base_storage, (uint8_t *)buffer + out_pos, physical_offset, bytes_to_write) != bytes_to_write) + return 0; + + out_pos += bytes_to_write; + in_pos += bytes_to_write; + remaining -= bytes_to_write; + } + return out_pos; +} + +bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size) { + uint32_t old_block_count = (uint32_t)DIV_ROUND_UP(ctx->_length, ctx->block_size); + uint32_t new_block_count = (uint32_t)DIV_ROUND_UP(size, ctx->block_size); + + if (old_block_count == new_block_count) + return true; + + if (old_block_count == 0) { + ctx->initial_block = save_allocation_table_allocate(ctx->fat, new_block_count); + if (ctx->initial_block == 0xFFFFFFFF) { + EPRINTF("Not enough space to resize file!"); + return false; + } + ctx->_length = new_block_count * ctx->block_size; + return true; + } + + if (new_block_count == 0) { + save_allocation_table_free(ctx->fat, ctx->initial_block); + + ctx->initial_block = 0x80000000; + ctx->_length = 0; + return true; + } + + if (new_block_count > old_block_count) { + uint32_t new_blocks = save_allocation_table_allocate(ctx->fat, new_block_count - old_block_count); + if (new_blocks == 0xFFFFFFFF) { + EPRINTF("Not enough space to resize file!"); + return false; + } + if (!save_allocation_table_join(ctx->fat, ctx->initial_block, new_blocks)) + return false; + } else { + uint32_t old_blocks = save_allocation_table_trim(ctx->fat, ctx->initial_block, new_block_count); + if (old_blocks == 0xFFFFFFFF) { + EPRINTF("Failure to trim!"); + return false; + } + if (!save_allocation_table_free(ctx->fat, old_blocks)) + return false; + } + + ctx->_length = new_block_count * ctx->block_size; + + return true; +} diff --git a/bdk/libs/nx_savedata/allocation_table_storage.h b/bdk/libs/nx_savedata/allocation_table_storage.h new file mode 100644 index 0000000..86f55cf --- /dev/null +++ b/bdk/libs/nx_savedata/allocation_table_storage.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _ALLOCATION_TABLE_STORAGE_H_ +#define _ALLOCATION_TABLE_STORAGE_H_ + +#include "allocation_table.h" +#include "storage.h" + +#include + +typedef struct { + substorage *base_storage; + uint32_t block_size; + uint32_t initial_block; + allocation_table_ctx_t *fat; + uint64_t _length; +} allocation_table_storage_ctx_t; + +static ALWAYS_INLINE void save_allocation_table_storage_get_size(allocation_table_storage_ctx_t *ctx, uint64_t *out_size) { + *out_size = ctx->_length; +} + +void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block); +uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); +bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size); + +#endif diff --git a/bdk/libs/nx_savedata/cached_storage.c b/bdk/libs/nx_savedata/cached_storage.c new file mode 100644 index 0000000..52d38a3 --- /dev/null +++ b/bdk/libs/nx_savedata/cached_storage.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "cached_storage.h" + +#include +#include + +#include + +static ALWAYS_INLINE cache_block_t *cache_block_init(cached_storage_ctx_t *ctx) { + cache_block_t *block = calloc(1, sizeof(cache_block_t)); + block->buffer = malloc(ctx->block_size); + block->index = -1; + return block; +} + +void save_cached_storage_init(cached_storage_ctx_t *ctx, substorage *base_storage, uint32_t block_size, uint32_t cache_size) { + memcpy(&ctx->base_storage, base_storage, sizeof(substorage)); + ctx->block_size = block_size; + substorage_get_size(base_storage, &ctx->length); + ctx->cache_size = cache_size; + + list_init(&ctx->blocks); + for (uint32_t i = 0; i < cache_size; i++) { + cache_block_t *block = cache_block_init(ctx); + list_append(&ctx->blocks, &block->link); + } +} + +void save_cached_storage_init_from_sector_storage(cached_storage_ctx_t *ctx, sector_storage *base_storage, uint32_t cache_size) { + save_cached_storage_init(ctx, &base_storage->base_storage, base_storage->sector_size, cache_size); +} + +static void cache_block_finalize(cache_block_t **block) { + free((*block)->buffer); + free(*block); +} + +void save_cached_storage_finalize(cached_storage_ctx_t *ctx) { + LIST_FOREACH_SAFE(curr_block, &ctx->blocks) { + cache_block_t *block = CONTAINER_OF(curr_block, cache_block_t, link) ; + cache_block_finalize(&block); + } +} + +static bool try_get_block_by_value(cached_storage_ctx_t *ctx, uint64_t index, cache_block_t **out_block) { + LIST_FOREACH_ENTRY(cache_block_t, block, &ctx->blocks, link) { + if (block->index == index) { + *out_block = block; + return true; + } + } + return false; +} + +static bool flush_block(cached_storage_ctx_t *ctx, cache_block_t *block) { + if (!block->dirty) + return true; + + uint64_t offset = block->index * ctx->block_size; + if (substorage_write(&ctx->base_storage, block->buffer, offset, block->length) != block->length) { + EPRINTF("Cached storage: Failed to write block!"); + return false; + } + block->dirty = false; + + return true; +} + +static bool read_block(cached_storage_ctx_t *ctx, cache_block_t *block, uint64_t index) { + uint64_t offset = index * ctx->block_size; + uint32_t length = ctx->block_size; + + if (ctx->length != -1) + length = (uint32_t)MIN(ctx->length - offset, length); + + if (substorage_read(&ctx->base_storage, block->buffer, offset, length) != length) { + EPRINTF("Cached storage: Failed to read block!"); + return false; + } + block->length = length; + block->index = index; + block->dirty = false; + + return true; +} + +static cache_block_t *get_block(cached_storage_ctx_t *ctx, uint64_t block_index) { + cache_block_t *block = NULL; + if (try_get_block_by_value(ctx, block_index, &block)) { + // Promote most recently used block to front of list if not already. + if (ctx->blocks.next != &block->link) { + list_remove(&block->link); + list_prepend(&ctx->blocks, &block->link); + } + return block; + } + + // Get a pointer either to the least recently used block or to a newly allocated block if storage is empty. + bool block_is_new = false; + if (ctx->blocks.prev != &ctx->blocks) { + block = CONTAINER_OF(ctx->blocks.prev, cache_block_t, link); + if (!flush_block(ctx, block)) + return NULL; + + // Remove least recently used block from list. + list_remove(&block->link); + } else { + block = cache_block_init(ctx); + block_is_new = true; + } + + if (!read_block(ctx, block, block_index)) { + if (block_is_new) + cache_block_finalize(&block); + return NULL; + } + + list_prepend(&ctx->blocks, &block->link); + + return block; +} + +uint32_t save_cached_storage_read(cached_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + uint64_t remaining = count; + uint64_t in_offset = offset; + uint32_t out_offset = 0; + + if (!is_range_valid(offset, count, ctx->length)) { + EPRINTF("Cached storage read out of range!"); + return 0; + } + + while (remaining) { + uint64_t block_index = in_offset / ctx->block_size; + uint32_t block_pos = (uint32_t)(in_offset % ctx->block_size); + cache_block_t *block = get_block(ctx,block_index); + if (!block) { + EPRINTFARGS("Cached storage read: Unable to get block\n at index %x", (uint32_t)block_index); + return 0; + } + + uint32_t bytes_to_read = (uint32_t)MIN(remaining, ctx->block_size - block_pos); + + memcpy((uint8_t *)buffer + out_offset, block->buffer + block_pos, bytes_to_read); + + out_offset += bytes_to_read; + in_offset += bytes_to_read; + remaining -= bytes_to_read; + } + + return out_offset; +} + +uint32_t save_cached_storage_write(cached_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + uint64_t remaining = count; + uint64_t in_offset = offset; + uint32_t out_offset = 0; + + if (!is_range_valid(offset, count, ctx->length)) { + EPRINTF("Cached storage write out of range!"); + return 0; + } + + while (remaining) { + uint64_t block_index = in_offset / ctx->block_size; + uint32_t block_pos = (uint32_t)(in_offset % ctx->block_size); + cache_block_t *block = get_block(ctx,block_index); + if (!block) { + EPRINTFARGS("Cached storage write: Unable to get block\n at index %x", (uint32_t)block_index); + return 0; + } + + uint32_t bytes_to_write = (uint32_t)MIN(remaining, ctx->block_size - block_pos); + + memcpy(block->buffer + block_pos, (uint8_t *)buffer + out_offset, bytes_to_write); + + block->dirty = true; + + out_offset += bytes_to_write; + in_offset += bytes_to_write; + remaining -= bytes_to_write; + } + + return out_offset; +} + +bool save_cached_storage_flush(cached_storage_ctx_t *ctx) { + LIST_FOREACH_ENTRY(cache_block_t, block, &ctx->blocks, link) { + if (!flush_block(ctx, block)) + return false; + } + + return true; +} diff --git a/bdk/libs/nx_savedata/cached_storage.h b/bdk/libs/nx_savedata/cached_storage.h new file mode 100644 index 0000000..3bd7880 --- /dev/null +++ b/bdk/libs/nx_savedata/cached_storage.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _CACHED_STORAGE_H_ +#define _CACHED_STORAGE_H_ + +#include "storage.h" + +#include +#include + +#include + +typedef struct { + uint64_t index; + uint8_t *buffer; + uint32_t length; + bool dirty; + link_t link; +} cache_block_t; + +typedef struct { + substorage base_storage; + uint32_t block_size; + uint64_t length; + uint32_t cache_size; + link_t blocks; +} cached_storage_ctx_t; + +void save_cached_storage_init(cached_storage_ctx_t *ctx, substorage *base_storage, uint32_t block_size, uint32_t cache_size); +void save_cached_storage_init_from_sector_storage(cached_storage_ctx_t *ctx, sector_storage *base_storage, uint32_t cache_size); +void save_cached_storage_finalize(cached_storage_ctx_t *ctx); +uint32_t save_cached_storage_read(cached_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_cached_storage_write(cached_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); +bool save_cached_storage_flush(cached_storage_ctx_t *ctx); + +#endif diff --git a/bdk/libs/nx_savedata/directory_entry.h b/bdk/libs/nx_savedata/directory_entry.h new file mode 100644 index 0000000..797966d --- /dev/null +++ b/bdk/libs/nx_savedata/directory_entry.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _DIRECTORY_ENTRY_H_ +#define _DIRECTORY_ENTRY_H_ + +#include + +typedef enum { + OPEN_DIR_MODE_DIR = 1, + OPEN_DIR_MODE_FILE = 2, + OPEN_DIR_MODE_NO_FILE_SIZE = -2147483648, + OPEN_DIR_MODE_ALL = OPEN_DIR_MODE_DIR | OPEN_DIR_MODE_FILE +} open_directory_mode_t; + +typedef enum { + DIR_ENT_TYPE_DIR = 0, + DIR_ENT_TYPE_FILE +} directory_entry_type_t; + +typedef struct { + char name[0x301]; + uint8_t attributes; + uint8_t _0x302[2]; + directory_entry_type_t type; + uint64_t size; +} directory_entry_t; + +#endif diff --git a/bdk/libs/nx_savedata/duplex_storage.c b/bdk/libs/nx_savedata/duplex_storage.c new file mode 100644 index 0000000..d7c4926 --- /dev/null +++ b/bdk/libs/nx_savedata/duplex_storage.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "duplex_storage.h" + +#include +#include + +void save_duplex_storage_init(duplex_storage_ctx_t *ctx, uint8_t *data_a, uint8_t *data_b, uint32_t block_size_power, void *bitmap, uint64_t bitmap_size) { + substorage_init(&ctx->data_a, &memory_storage_vt, data_a, 0, ctx->_length); + substorage_init(&ctx->data_b, &memory_storage_vt, data_b, 0, ctx->_length); + substorage_init(&ctx->bitmap_storage, &memory_storage_vt, bitmap, 0, bitmap_size); + ctx->block_size = 1 << block_size_power; + + ctx->bitmap.data = (uint8_t *)bitmap; + ctx->bitmap.bitmap = malloc(bitmap_size >> 3); + + uint32_t bits_remaining = (uint32_t)bitmap_size; + uint32_t bitmap_pos = 0; + uint32_t *buffer_pos = (uint32_t *)ctx->bitmap.data; + while (bits_remaining) { + uint32_t bits_to_read = MIN(bits_remaining, 0x20); + uint32_t val = *buffer_pos; + for (uint32_t i = 0; i < bits_to_read; i++) { + if (val & 0x80000000) + save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos); + else + save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos); + bitmap_pos++; + bits_remaining--; + val <<= 1; + } + buffer_pos++; + } +} + +uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint32_t bytes_to_read = MIN(ctx->block_size - block_pos, remaining); + + substorage *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? &ctx->data_b : &ctx->data_a; + if (substorage_read(data, (uint8_t *)buffer + out_pos, in_pos, bytes_to_read) != bytes_to_read) + return 0; + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +uint32_t save_duplex_storage_write(duplex_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint32_t bytes_to_write = MIN(ctx->block_size - block_pos, remaining); + + substorage *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? &ctx->data_b : &ctx->data_a; + if (substorage_write(data, (uint8_t *)buffer + out_pos, in_pos, bytes_to_write) != bytes_to_write) + return 0; + + out_pos += bytes_to_write; + in_pos += bytes_to_write; + remaining -= bytes_to_write; + } + return out_pos; +} \ No newline at end of file diff --git a/bdk/libs/nx_savedata/duplex_storage.h b/bdk/libs/nx_savedata/duplex_storage.h new file mode 100644 index 0000000..212a0f6 --- /dev/null +++ b/bdk/libs/nx_savedata/duplex_storage.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _DUPLEX_STORAGE_H_ +#define _DUPLEX_STORAGE_H_ + +#include "storage.h" + +#include + +#define DUPLEX_BITMAP_SIZE_BITS 0x200 +#define DUPLEX_BITMAP_SIZE_BYTES 0x40 + +typedef struct { + uint8_t *data; + uint8_t *bitmap; +} duplex_bitmap_t; + +typedef struct { + uint32_t block_size; + substorage bitmap_storage; + substorage data_a; + substorage data_b; + duplex_bitmap_t bitmap; + uint64_t _length; + substorage base_storage; +} duplex_storage_ctx_t; + +static ALWAYS_INLINE void save_bitmap_set_bit(void *buffer, uint64_t bit_offset) { + *((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7); +} + +static ALWAYS_INLINE void save_bitmap_clear_bit(void *buffer, uint64_t bit_offset) { + *((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7)); +} + +static ALWAYS_INLINE uint8_t save_bitmap_check_bit(const void *buffer, uint64_t bit_offset) { + return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7)); +} + +void save_duplex_storage_init(duplex_storage_ctx_t *ctx, uint8_t *data_a, uint8_t *data_b, uint32_t block_size_power, void *bitmap, uint64_t bitmap_size); +uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_duplex_storage_write(duplex_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); + +#endif diff --git a/bdk/libs/nx_savedata/fs_int64.h b/bdk/libs/nx_savedata/fs_int64.h new file mode 100644 index 0000000..a814e47 --- /dev/null +++ b/bdk/libs/nx_savedata/fs_int64.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * Copyright (c) 2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FS_INT64_H_ +#define _FS_INT64_H_ + +#include + +#include + +/* For 64-bit integers which are 4-byte aligned but not 8-byte aligned. */ +typedef struct { + uint32_t low; + uint32_t high; +} fs_int64_t; + +static ALWAYS_INLINE void fs_int64_set(fs_int64_t *i, int64_t val) { + i->low = (uint32_t)((val & (uint64_t)(0x00000000FFFFFFFFul)) >> 0); + i->high = (uint32_t)((val & (uint64_t)(0xFFFFFFFF00000000ul)) >> 32); +} + +static ALWAYS_INLINE const int64_t fs_int64_get(fs_int64_t *i) { + return ((int64_t)(i->high) << 32) | ((int64_t)i->low); +} + +#endif diff --git a/bdk/libs/nx_savedata/header.h b/bdk/libs/nx_savedata/header.h new file mode 100644 index 0000000..3d65d83 --- /dev/null +++ b/bdk/libs/nx_savedata/header.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _HEADER_H_ +#define _HEADER_H_ + +#include "allocation_table.h" +#include "duplex_storage.h" +#include "fs_int64.h" +#include "hierarchical_integrity_verification_storage.h" +#include "journal_map.h" +#include "journal_storage.h" +#include "remap_storage.h" + +#include +#include + +#define MAGIC_DISF 0x46534944 +#define MAGIC_DPFS 0x53465044 +#define MAGIC_JNGL 0x4C474E4A +#define MAGIC_SAVE 0x45564153 +#define MAGIC_RMAP 0x50414D52 +#define MAGIC_IVFC 0x43465649 + +#define VERSION_DISF_LEEGACY 0x40000 +#define VERSION_DISF_5 0x50000 +#define VERSION_DPFS 0x10000 +#define VERSION_JNGL 0x10000 +#define VERSION_SAVE 0x60000 +#define VERSION_RMAP 0x10000 +#define VERSION_IVFC 0x20000 + +#define SAVE_BLOCK_SIZE_DEFAULT 0x4000 + +#define SAVE_NUM_HEADERS 2 + +typedef struct { + uint32_t magic; /* DISF */ + uint32_t version; + uint8_t hash[0x20]; + uint64_t file_map_entry_offset; + uint64_t file_map_entry_size; + uint64_t meta_map_entry_offset; + uint64_t meta_map_entry_size; + uint64_t file_map_data_offset; + uint64_t file_map_data_size; + uint64_t duplex_l1_offset_a; + uint64_t duplex_l1_offset_b; + uint64_t duplex_l1_size; + uint64_t duplex_data_offset_a; + uint64_t duplex_data_offset_b; + uint64_t duplex_data_size; + uint64_t journal_data_offset; + uint64_t journal_data_size_a; + uint64_t journal_data_size_b; + uint64_t journal_size; + uint64_t duplex_master_offset_a; + uint64_t duplex_master_offset_b; + uint64_t duplex_master_size; + uint64_t ivfc_master_hash_offset_a; + uint64_t ivfc_master_hash_offset_b; + uint64_t ivfc_master_hash_size; + uint64_t journal_map_table_offset; + uint64_t journal_map_table_size; + uint64_t journal_physical_bitmap_offset; + uint64_t journal_physical_bitmap_size; + uint64_t journal_virtual_bitmap_offset; + uint64_t journal_virtual_bitmap_size; + uint64_t journal_free_bitmap_offset; + uint64_t journal_free_bitmap_size; + uint64_t ivfc_l1_offset; + uint64_t ivfc_l1_size; + uint64_t ivfc_l2_offset; + uint64_t ivfc_l2_size; + uint64_t ivfc_l3_offset; + uint64_t ivfc_l3_size; + uint64_t fat_offset; + uint64_t fat_size; + uint8_t duplex_index; + uint64_t fat_ivfc_master_hash_a; + uint64_t fat_ivfc_master_hash_b; + uint64_t fat_ivfc_l1_offset; + uint64_t fat_ivfc_l1_size; + uint64_t fat_ivfc_l2_offset; + uint64_t fat_ivfc_l2_size; + uint8_t _0x190[0x70]; +} fs_layout_t; + +static_assert(sizeof(fs_layout_t) == 0x200, "Save filesystem layout header size is wrong!"); + +typedef struct { + fs_int64_t offset; + fs_int64_t length; + uint32_t block_size_power; +} duplex_info_t; + +static_assert(sizeof(duplex_info_t) == 0x14, "Duplex info size is wrong!"); + +typedef enum { + DUPLEX_LAYER_MASTER = 0, + DUPLEX_LAYER_1 = 1, + DUPLEX_LAYER_2 = 2, +} duplex_layer_t; + +typedef struct { + uint32_t magic; /* DPFS */ + uint32_t version; + duplex_info_t layers[3]; +} duplex_header_t; + +typedef struct { + uint64_t level_block_size[2]; +} duplex_storage_control_input_param_t; + +static_assert(sizeof(duplex_header_t) == 0x44, "Duplex header size is wrong!"); + +typedef struct { + uint8_t id[0x10]; +} account_user_id_t; + +typedef enum { + SAVE_TYPE_SYSTEM = 0, + SAVE_TYPE_ACCOUNT = 1, + SAVE_TYPE_BCAT = 2, + SAVE_TYPE_DEVICE = 3, + SAVE_TYPE_TEMP = 4, + SAVE_TYPE_CACHE = 5, + SAVE_TYPE_SYSTEM_BCAT = 6 +} save_data_type_t; + +typedef enum { + SAVE_RANK_PRIMARY = 0, + SAVE_RANK_SECONDARY = 1, +} save_data_rank_t; + +typedef struct { + uint64_t program_id; + account_user_id_t user_id; + uint64_t save_id; + uint8_t save_data_type; + uint8_t save_data_rank; + uint16_t save_data_index; + uint8_t _0x24[0x1C]; +} save_data_attribute_t; + +static_assert(sizeof(save_data_attribute_t) == 0x40, "Save data attribute size is wrong!"); + +typedef enum { + SAVE_FLAG_KEEP_AFTER_RESETTING_SYSTEM_SAVE_DATA = 1, + SAVE_FLAG_KEEP_AFTER_REFURBISHMENT = 2, + SAVE_FLAG_KEEP_AFTER_RESETTING_SYSTEM_SAVE_DATA_WITHOUT_USER_SAVE_DATA = 4, + SAVE_FLAG_NEEDS_SECURE_DELETE = 8, +} save_data_flags_t; + +typedef struct { + save_data_attribute_t save_data_attribute; + uint64_t save_owner_id; + uint64_t timestamp; + uint32_t flags; + uint8_t _0x54[4]; + uint64_t savedata_size; + uint64_t journal_size; + uint64_t commit_id; + uint8_t reserved[0x190]; +} extra_data_t; + +static_assert(sizeof(extra_data_t) == 0x200, "Extra data size is wrong!"); + +typedef struct { + uint32_t magic; /* SAVE */ + uint32_t version; + uint64_t block_count; + uint64_t block_size; + allocation_table_header_t fat_header; +} save_fs_header_t; + +static_assert(sizeof(save_fs_header_t) == 0x48, "Save filesystem header size is wrong!"); + +typedef struct { + uint8_t cmac[0x10]; + uint8_t _0x10[0xF0]; + fs_layout_t layout; + duplex_header_t duplex_header; + ivfc_save_hdr_t data_ivfc_header; + uint32_t _0x404; + journal_header_t journal_header; + save_fs_header_t save_header; + remap_header_t main_remap_header, meta_remap_header; + uint64_t _0x6D0; + extra_data_t extra_data_a; + extra_data_t extra_data_b; + union { + struct { + ivfc_save_hdr_t fat_ivfc_header; + uint64_t _0xB98; + uint8_t additional_data[0x3460]; + } version_5; + struct { + uint8_t additional_data[0x3528]; + } legacy; + }; +} save_header_t; + +static_assert(sizeof(save_header_t) == 0x4000, "Save header size is wrong!"); + +#endif diff --git a/bdk/libs/nx_savedata/hierarchical_duplex_storage.c b/bdk/libs/nx_savedata/hierarchical_duplex_storage.c new file mode 100644 index 0000000..bcdcb27 --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_duplex_storage.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "hierarchical_duplex_storage.h" + +#include +#include + +void save_duplex_fs_layer_info_init(duplex_fs_layer_info_t *ctx, uint8_t *data_a, uint8_t *data_b, duplex_info_t *info) { + if (data_a) + ctx->data_a = data_a; + if (data_b) + ctx->data_b = data_b; + ctx->info.offset = info->offset; + ctx->info.length = info->length; + ctx->info.block_size_power = info->block_size_power; +} + +bool save_hierarchical_duplex_storage_init(hierarchical_duplex_storage_ctx_t *ctx, remap_storage_ctx_t *storage, save_header_t *header) { + substorage base_storage; + substorage_init(&base_storage, &remap_storage_vt, storage, 0, -1); + fs_layout_t *layout = &header->layout; + duplex_fs_layer_info_t duplex_layers[3]; + + save_duplex_fs_layer_info_init(&duplex_layers[0], (uint8_t *)header + layout->duplex_master_offset_a, (uint8_t *)header + layout->duplex_master_offset_b, &header->duplex_header.layers[0]); + + duplex_layers[1].data_a = malloc(layout->duplex_l1_size); + duplex_layers[1].data_b = malloc(layout->duplex_l1_size); + if (substorage_read(&base_storage, duplex_layers[1].data_a, layout->duplex_l1_offset_a, layout->duplex_l1_size) != layout->duplex_l1_size) { + EPRINTF("Hier dup init: Failed to read L1 bitmap A!"); + return false; + } + if (substorage_read(&base_storage, duplex_layers[1].data_b, layout->duplex_l1_offset_b, layout->duplex_l1_size) != layout->duplex_l1_size) { + EPRINTF("Hier dup init: Failed to read L1 bitmap B!"); + return false; + } + save_duplex_fs_layer_info_init(&duplex_layers[1], NULL, NULL, &header->duplex_header.layers[1]); + + duplex_layers[2].data_a = malloc(layout->duplex_data_size); + duplex_layers[2].data_b = malloc(layout->duplex_data_size); + if (substorage_read(&base_storage, duplex_layers[2].data_a, layout->duplex_data_offset_a, layout->duplex_data_size) != layout->duplex_data_size) { + EPRINTF("Hier dup init: Failed to read duplex data A!"); + return false; + } + if (substorage_read(&base_storage, duplex_layers[2].data_b, layout->duplex_data_offset_b, layout->duplex_data_size) != layout->duplex_data_size) { + EPRINTF("Hier dup init: Failed to read duplex data B!"); + return false; + } + save_duplex_fs_layer_info_init(&duplex_layers[2], NULL, NULL, &header->duplex_header.layers[2]); + + uint8_t *bitmap = layout->duplex_index == 1 ? duplex_layers[0].data_b : duplex_layers[0].data_a; + ctx->layers[0]._length = layout->duplex_l1_size; + save_duplex_storage_init(&ctx->layers[0], duplex_layers[1].data_a, duplex_layers[1].data_b, duplex_layers[1].info.block_size_power, bitmap, layout->duplex_master_size); + + bitmap = malloc(ctx->layers[0]._length); + if (save_duplex_storage_read(&ctx->layers[0], bitmap, 0, ctx->layers[0]._length) != ctx->layers[0]._length) { + EPRINTF("Hier dup init: Failed to read bitmap!"); + return false; + } + ctx->layers[1]._length = layout->duplex_data_size; + save_duplex_storage_init(&ctx->layers[1], duplex_layers[2].data_a, duplex_layers[2].data_b, duplex_layers[2].info.block_size_power, bitmap, ctx->layers[0]._length); + + ctx->data_layer = &ctx->layers[1]; + ctx->_length = ctx->data_layer->_length; + + return true; +} + +bool save_hierarchical_duplex_storage_flush(hierarchical_duplex_storage_ctx_t *ctx, remap_storage_ctx_t *storage, save_header_t *header) { + substorage base_storage; + substorage_init(&base_storage, &remap_storage_vt, storage, 0, -1); + fs_layout_t *layout = &header->layout; + + if (save_duplex_storage_write(&ctx->layers[0], &ctx->layers[1].bitmap.data, 0, ctx->layers[0]._length) != ctx->layers[0]._length) { + EPRINTF("Hier dup flush: Failed to write bitmap!"); + return false; + } + + if (substorage_write(&base_storage, ctx->layers[1].data_a.base_storage.ctx, layout->duplex_data_offset_a, layout->duplex_data_size) != layout->duplex_data_size) { + EPRINTF("Hier dup flush: Failed to write data A!"); + return false; + } + if (substorage_write(&base_storage, ctx->layers[1].data_b.base_storage.ctx, layout->duplex_data_offset_b, layout->duplex_data_size) != layout->duplex_data_size) { + EPRINTF("Hier dup flush: Failed to write data B!"); + return false; + } + + return true; +} diff --git a/bdk/libs/nx_savedata/hierarchical_duplex_storage.h b/bdk/libs/nx_savedata/hierarchical_duplex_storage.h new file mode 100644 index 0000000..4353d6d --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_duplex_storage.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _HIER_DUPLEX_STORAGE_H_ +#define _HIER_DUPLEX_STORAGE_H_ + +#include "duplex_storage.h" +#include "header.h" +#include "remap_storage.h" +#include "storage.h" + +#include + +typedef struct { + duplex_storage_ctx_t layers[2]; + duplex_storage_ctx_t *data_layer; + uint64_t _length; + substorage storage; +} hierarchical_duplex_storage_ctx_t; + +typedef struct { + uint8_t *data_a; + uint8_t *data_b; + duplex_info_t info; +} duplex_fs_layer_info_t; + +bool save_hierarchical_duplex_storage_init(hierarchical_duplex_storage_ctx_t *ctx, remap_storage_ctx_t *storage, save_header_t *header); +bool save_hierarchical_duplex_storage_flush(hierarchical_duplex_storage_ctx_t *ctx, remap_storage_ctx_t *storage, save_header_t *header); + +#endif diff --git a/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c new file mode 100644 index 0000000..4d8153b --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "hierarchical_integrity_verification_storage.h" + +#include "header.h" + +#include +#include + +#include + +void save_hierarchical_integrity_verification_storage_control_area_query_size(ivfc_size_set_t *out, const ivfc_storage_control_input_param_t *input_param, int32_t layer_count, uint64_t data_size) { + int64_t level_size[IVFC_MAX_LEVEL + 1]; + int32_t level = layer_count - 1; + + out->control_size = sizeof(ivfc_save_hdr_t); + + level_size[level] = ALIGN(data_size, input_param->level_block_size[level - 1]); + level--; + + for ( ; level > 0; --level) { + level_size[level] = ALIGN(level_size[level + 1] / input_param->level_block_size[level] * 0x20, input_param->level_block_size[level - 1]); + } + + level_size[0] = 0x20 * level_size[1] / input_param->level_block_size[0]; + out->master_hash_size = level_size[0]; + + for (level = 1; level < layer_count - 1; ++level) { + out->layered_hash_sizes[level - 1] = level_size[level]; + } +} + +bool save_hierarchical_integrity_verification_storage_control_area_expand(substorage *storage, const ivfc_save_hdr_t *header) { + return substorage_write(storage, header, 0, sizeof(ivfc_save_hdr_t)) == sizeof(ivfc_save_hdr_t); +} + +void save_hierarchical_integrity_verification_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, integrity_verification_info_ctx_t *level_info, uint64_t num_levels, int integrity_check_level) { + ctx->integrity_check_level = integrity_check_level; + ctx->level_validities = malloc(sizeof(validity_t *) * (num_levels - 1)); + memcpy(&ctx->levels[0].base_storage, &level_info[0].data, sizeof(substorage)); + for (unsigned int i = 1; i < num_levels; i++) { + integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1]; + save_ivfc_storage_init(level_data, &level_info[i], &ctx->levels[i - 1].base_storage, integrity_check_level); + + uint64_t level_size = level_data->base_storage.length; + uint32_t cache_count = MIN((uint32_t)(DIV_ROUND_UP(level_size, level_info[i].block_size)), 4); + save_cached_storage_init_from_sector_storage(&ctx->levels[i], &level_data->base_storage, cache_count); + substorage_init(&ctx->levels[i].base_storage, &ivfc_storage_vt, level_data, 0, level_info[i].data.length); + + ctx->level_validities[i - 1] = level_data->block_validities; + } + ctx->data_level = &ctx->levels[num_levels - 1]; + ctx->length = ctx->data_level->length; + substorage_init(&ctx->base_storage, &hierarchical_integrity_verification_storage_vt, ctx, 0, ctx->length); +} + +void save_hierarchical_integrity_verification_storage_get_ivfc_info(integrity_verification_info_ctx_t *init_info, ivfc_save_hdr_t *header, uint64_t num_levels, substorage *levels) { + struct salt_source_t { + char string[64]; + uint32_t length; + }; + + static const struct salt_source_t salt_sources[IVFC_MAX_LEVEL] = { + {"HierarchicalIntegrityVerificationStorage::Master", 48}, + {"HierarchicalIntegrityVerificationStorage::L1", 44}, + {"HierarchicalIntegrityVerificationStorage::L2", 44}, + {"HierarchicalIntegrityVerificationStorage::L3", 44}, + {"HierarchicalIntegrityVerificationStorage::L4", 44}, + {"HierarchicalIntegrityVerificationStorage::L5", 44} + }; + + memcpy(&init_info[0].data, &levels[0], sizeof(substorage)); + init_info[0].block_size = 0; + for (unsigned int i = 1; i < num_levels; i++) { + memcpy(&init_info[i].data, &levels[i], sizeof(substorage)); + init_info[i].block_size = 1 << header->level_hash_info.level_headers[i - 1].block_size; + se_calc_hmac_sha256(init_info[i].salt, &header->level_hash_info.seed, sizeof(hash_salt_t), salt_sources[i - 1].string, salt_sources[i - 1].length); + } +} + +static void save_hierarchical_integrity_verification_storage_to_storage_list(substorage *levels, ivfc_save_hdr_t *header, substorage *master_hash, substorage *data) { + memcpy(&levels[0], master_hash, sizeof(substorage)); + for (unsigned int i = 0; i < 3; i++) { + ivfc_level_hdr_t *level = &header->level_hash_info.level_headers[i]; + substorage_init(&levels[i + 1], &remap_storage_vt, data, fs_int64_get(&level->logical_offset), fs_int64_get(&level->hash_data_size)); + } +} + +void save_hierarchical_integrity_verification_storage_init_with_levels(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *header, uint64_t num_levels, substorage *levels, int integrity_check_level) { + integrity_verification_info_ctx_t init_info[IVFC_MAX_LEVEL]; + save_hierarchical_integrity_verification_storage_get_ivfc_info(init_info, header, num_levels, levels); + save_hierarchical_integrity_verification_storage_init(ctx, init_info, num_levels, integrity_check_level); +} + +void save_hierarchical_integrity_verification_storage_init_for_fat(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *header, substorage *master_hash, substorage *data, int integrity_check_level) { + const uint32_t ivfc_levels = IVFC_MAX_LEVEL - 2; + substorage levels[ivfc_levels + 1]; + save_hierarchical_integrity_verification_storage_to_storage_list(levels, header, master_hash, data); + save_hierarchical_integrity_verification_storage_init_with_levels(ctx, header, ivfc_levels, levels, integrity_check_level); +} + +validity_t save_hierarchical_integrity_verification_storage_validate(hierarchical_integrity_verification_storage_ctx_t *ctx) { + validity_t result = VALIDITY_VALID; + integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[3]; + + uint64_t block_size = storage->base_storage.sector_size; + uint32_t block_count = (uint32_t)(DIV_ROUND_UP(ctx->length, block_size)); + + uint8_t *buffer = malloc(block_size); + + for (unsigned int i = 0; i < block_count; i++) { + if (ctx->level_validities[3][i] == VALIDITY_UNCHECKED) { + uint64_t storage_size = storage->base_storage.length; + uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), (uint32_t)block_size); + substorage_read(&ctx->data_level->base_storage, buffer, block_size * i, to_read); + } + if (ctx->level_validities[3][i] == VALIDITY_INVALID) { + result = VALIDITY_INVALID; + break; + } + } + free(buffer); + + return result; +} + +void save_hierarchical_integrity_verification_storage_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx) { + for (unsigned int i = 0; i < IVFC_MAX_LEVEL - 2; i++) { + validity_t level_validity = VALIDITY_VALID; + for (unsigned int j = 0; j < ctx->integrity_storages[i].base_storage.sector_count; j++) { + if (ctx->level_validities[i][j] == VALIDITY_INVALID) { + level_validity = VALIDITY_INVALID; + break; + } + if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) { + level_validity = VALIDITY_UNCHECKED; + } + } + ctx->hash_validity[i] = level_validity; + } +} + diff --git a/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.h b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.h new file mode 100644 index 0000000..fd1c798 --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _HIVFC_H_ +#define _HIVFC_H_ + +#include "cached_storage.h" +#include "fs_int64.h" +#include "integrity_verification_storage.h" +#include "storage.h" + +#include + +#include +#include + +#define IVFC_MAX_LEVEL 6 + +typedef struct { + fs_int64_t logical_offset; + fs_int64_t hash_data_size; + uint32_t block_size; + uint8_t reserved[4]; +} ivfc_level_hdr_t; + +typedef struct { + ivfc_level_hdr_t *hdr; + validity_t hash_validity; +} ivfc_level_save_ctx_t; + +typedef struct { + uint8_t val[0x20]; +} hash_salt_t; + +typedef struct { + uint32_t num_levels; + ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL]; + hash_salt_t seed; +} ivfc_level_hash_info_t; + +typedef struct { + uint32_t magic; + uint32_t version; + uint32_t master_hash_size; + ivfc_level_hash_info_t level_hash_info; +} ivfc_save_hdr_t; + +static_assert(sizeof(ivfc_save_hdr_t) == 0xC0, "Ivfc header size invalid!"); + +typedef struct { + int64_t control_size; + int64_t master_hash_size; + int64_t layered_hash_sizes[IVFC_MAX_LEVEL]; +} ivfc_size_set_t; + +typedef struct { + uint64_t level_block_size[IVFC_MAX_LEVEL]; +} ivfc_storage_control_input_param_t; + +typedef struct { + cached_storage_ctx_t levels[IVFC_MAX_LEVEL - 1]; + cached_storage_ctx_t *data_level; + int integrity_check_level; + validity_t **level_validities; + uint64_t length; + integrity_verification_storage_ctx_t integrity_storages[IVFC_MAX_LEVEL - 2]; + validity_t hash_validity[IVFC_MAX_LEVEL - 2]; + substorage base_storage; +} hierarchical_integrity_verification_storage_ctx_t; + +void save_hierarchical_integrity_verification_storage_control_area_query_size(ivfc_size_set_t *out, const ivfc_storage_control_input_param_t *input_param, int32_t layer_count, uint64_t data_size); +bool save_hierarchical_integrity_verification_storage_control_area_expand(substorage *header_storage, const ivfc_save_hdr_t *header); +void save_hierarchical_integrity_verification_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, integrity_verification_info_ctx_t *level_info, uint64_t num_levels, int integrity_check_level); +void save_hierarchical_integrity_verification_storage_init_with_levels(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *header, uint64_t num_levels, substorage *levels, int integrity_check_level); +void save_hierarchical_integrity_verification_storage_init_for_fat(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *header, substorage *master_hash, substorage *data, int integrity_check_level); +validity_t save_hierarchical_integrity_verification_storage_validate(hierarchical_integrity_verification_storage_ctx_t *ctx); +void save_hierarchical_integrity_verification_storage_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx); + +#endif diff --git a/bdk/libs/nx_savedata/hierarchical_save_file_table.c b/bdk/libs/nx_savedata/hierarchical_save_file_table.c new file mode 100644 index 0000000..0ae9126 --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_save_file_table.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "hierarchical_save_file_table.h" +#include "path_parser.h" + +#include + +#include + +bool save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_entry_key_t *key) { + path_parser_ctx_t parser; + if (!save_path_parser_init(&parser, path)) { + EPRINTF("Failed to init path parser!"); + return false; + } + + uint32_t current_len = 0; + const char *current = save_path_parser_get_current(&parser, ¤t_len); + memset(key, 0, sizeof(save_entry_key_t)); + memcpy(key->name, current, current_len); + + while (!save_path_parser_is_finished(&parser)) { + key->parent = save_fs_list_get_index_from_key(&ctx->directory_table, key, NULL); + + if (key->parent & 0x80000000) + return false; + + save_path_parser_try_get_next(&parser, key->name); + } + return true; +} + +bool save_hierarchical_file_table_try_open_file(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_file_info_t *file_info) { + save_entry_key_t key; + if (!save_hierarchical_file_table_find_path_recursive(ctx, path, &key)) { + memset(file_info, 0, sizeof(save_file_info_t)); + return false; + } + + save_table_entry_t value; + if (save_fs_list_try_get_value_by_key(&ctx->file_table, &key, &value)) { + memcpy(file_info, &value.save_file_info, sizeof(save_file_info_t)); + return true; + } + + memset(file_info, 0, sizeof(save_file_info_t)); + return false; +} + +bool save_hierarchical_file_table_try_open_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_find_position_t *position) { + save_entry_key_t key; + if (!save_hierarchical_file_table_find_path_recursive(ctx, path, &key)) { + memset(position, 0, sizeof(save_find_position_t)); + return false; + } + + save_table_entry_t entry; + if (save_fs_list_try_get_value_by_key(&ctx->file_table, &key, &entry)) { + memcpy(position, &entry.save_find_position, sizeof(save_find_position_t)); + return true; + } + + memset(position, 0, sizeof(save_find_position_t)); + return false; +} + +bool save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) { + if (position->next_file == 0) { + memset(info, 0, sizeof(save_file_info_t)); + memset(name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); + return false; + } + + save_table_entry_t entry; + if (!save_fs_list_try_get_value_and_name(&ctx->file_table, position->next_file, &entry, name)) { + memset(info, 0, sizeof(save_file_info_t)); + memset(name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); + return false; + } + + position->next_file = entry.next_sibling; + memcpy(info, &entry.save_file_info, sizeof(save_file_info_t)); + return true; +} + +bool save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) { + if (position->next_directory == 0) { + return false; + } + + save_table_entry_t entry; + if(!save_fs_list_try_get_value_and_name(&ctx->directory_table, position->next_directory, &entry, name)) { + memset(name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); + return false; + } + + position->next_directory = entry.next_sibling; + return true; +} + +static bool save_hierarchical_file_table_link_file_to_parent(hierarchical_save_file_table_ctx_t *ctx, uint32_t parent_index, uint32_t file_index) { + save_table_entry_t parent_entry, file_entry; + if (!save_fs_list_get_value_by_index(&ctx->directory_table, parent_index, &parent_entry)) { + EPRINTF("Failed to get directory table value!"); + return false; + } + if (!save_fs_list_get_value_by_index(&ctx->file_table, file_index, &file_entry)) { + EPRINTF("Failed to get file table value!"); + return false; + } + + file_entry.next_sibling = parent_entry.save_find_position.next_file; + parent_entry.save_find_position.next_file = file_index; + + if (!save_fs_list_set_value(&ctx->directory_table, parent_index, &parent_entry)) { + EPRINTF("Failed to set directory table value!"); + return false; + } + if (!save_fs_list_set_value(&ctx->file_table, file_index, &file_entry)) { + EPRINTF("Failed to set file table value!"); + return false; + } + + return true; +} + + +static bool save_hierarchical_file_table_link_directory_to_parent(hierarchical_save_file_table_ctx_t *ctx, uint32_t parent_index, uint32_t dir_index) { + save_table_entry_t parent_entry, dir_entry; + if (!save_fs_list_get_value_by_index(&ctx->directory_table, parent_index, &parent_entry)) { + EPRINTF("Failed to get parent directory table value!"); + return false; + } + if (!save_fs_list_get_value_by_index(&ctx->directory_table, dir_index, &dir_entry)) { + EPRINTF("Failed to get directory table value!"); + return false; + } + + dir_entry.next_sibling = parent_entry.save_find_position.next_directory; + parent_entry.save_find_position.next_directory = dir_index; + + if (!save_fs_list_set_value(&ctx->directory_table, parent_index, &parent_entry)) { + EPRINTF("Failed to set parent directory table value!"); + return false; + } + if (!save_fs_list_set_value(&ctx->directory_table, dir_index, &dir_entry)) { + EPRINTF("Failed to set directory table value!"); + return false; + } + + return true; +} + +void save_hierarchical_file_table_unlink_file_from_parent(hierarchical_save_file_table_ctx_t *ctx, uint32_t parent_index, uint32_t file_index) { + save_table_entry_t parent_entry, file_entry; + save_fs_list_get_value_by_index(&ctx->directory_table, parent_index, &parent_entry); + save_fs_list_get_value_by_index(&ctx->file_table, file_index, &file_entry); + + if (parent_entry.save_find_position.next_file == file_index) { + parent_entry.save_find_position.next_file = file_entry.next_sibling; + save_fs_list_set_value(&ctx->directory_table, parent_index, &parent_entry); + return; + } + + uint32_t prev_index = parent_entry.save_find_position.next_file; + save_table_entry_t prev_entry, cur_entry; + save_fs_list_get_value_by_index(&ctx->file_table, prev_index, &prev_entry); + uint32_t cur_index = prev_entry.next_sibling; + + while (cur_index != 0) { + save_fs_list_get_value_by_index(&ctx->file_table, cur_index, &cur_entry); + if (cur_index == file_index) { + prev_entry.next_sibling = cur_entry.next_sibling; + save_fs_list_set_value(&ctx->file_table, prev_index, &prev_entry); + return; + } + prev_index = cur_index; + memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); + cur_index = prev_entry.next_sibling; + } +} + +void save_hierarchical_file_table_unlink_directory_from_parent(hierarchical_save_file_table_ctx_t *ctx, uint32_t parent_index, uint32_t dir_index) { + save_table_entry_t parent_entry, dir_entry; + save_fs_list_get_value_by_index(&ctx->directory_table, parent_index, &parent_entry); + save_fs_list_get_value_by_index(&ctx->directory_table, dir_index, &dir_entry); + + if (parent_entry.save_find_position.next_directory == dir_index) { + parent_entry.save_find_position.next_directory = dir_entry.next_sibling; + save_fs_list_set_value(&ctx->directory_table, parent_index, &parent_entry); + return; + } + + uint32_t prev_index = parent_entry.save_find_position.next_directory; + save_table_entry_t prev_entry, cur_entry; + save_fs_list_get_value_by_index(&ctx->directory_table, prev_index, &prev_entry); + uint32_t cur_index = prev_entry.next_sibling; + + while (cur_index != 0) { + save_fs_list_get_value_by_index(&ctx->directory_table, cur_index, &cur_entry); + if (cur_index == dir_index) { + prev_entry.next_sibling = cur_entry.next_sibling; + save_fs_list_set_value(&ctx->directory_table, prev_index, &prev_entry); + return; + } + prev_index = cur_index; + memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); + cur_index = prev_entry.next_sibling; + } +} + +bool save_hierarchical_file_table_delete_file(hierarchical_save_file_table_ctx_t *ctx, const char *path) { + save_entry_key_t key; + save_hierarchical_file_table_find_path_recursive(ctx, path, &key); + + uint32_t parent_index = key.parent; + uint32_t to_delete_index = save_fs_list_get_index_from_key(&ctx->file_table, &key, NULL); + + if (to_delete_index == 0xFFFFFFFF) { + EPRINTF("File not found!"); + return false; + } + + save_hierarchical_file_table_unlink_file_from_parent(ctx, parent_index, to_delete_index); + + return save_fs_list_remove(&ctx->file_table, &key); +} + +bool save_hierarchical_file_table_delete_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path) { + save_entry_key_t key; + save_hierarchical_file_table_find_path_recursive(ctx, path, &key); + + uint32_t parent_index = key.parent; + uint32_t to_delete_index = save_fs_list_get_index_from_key(&ctx->directory_table, &key, NULL); + if (to_delete_index == 0xFFFFFFFF) { + EPRINTF("Directory not found!"); + return false; + } + + save_table_entry_t to_delete_entry; + save_fs_list_get_value_by_index(&ctx->directory_table, to_delete_index, &to_delete_entry); + if (to_delete_entry.save_find_position.next_directory != 0 || to_delete_entry.save_find_position.next_file != 0) { + EPRINTF("Directory is not empty!"); + return false; + } + + save_hierarchical_file_table_unlink_directory_from_parent(ctx, parent_index, to_delete_index); + + return save_fs_list_remove(&ctx->directory_table, &key); +} + +bool save_hierarchical_file_table_rename_file(hierarchical_save_file_table_ctx_t *ctx, const char *src_path, const char *dst_path) { + save_file_info_t file_info; + save_find_position_t position; + save_entry_key_t old_key, new_key; + + if (strcmp(src_path, dst_path) == 0 || save_hierarchical_file_table_try_open_file(ctx, dst_path, &file_info) || save_hierarchical_file_table_try_open_directory(ctx, dst_path, &position)) { + EPRINTF("Destination path already exists!"); + return false; + } + + if (!save_hierarchical_file_table_find_path_recursive(ctx, src_path, &old_key)) { + EPRINTF("File not found!"); + return false; + } + + uint32_t file_index = save_fs_list_get_index_from_key(&ctx->file_table, &old_key, NULL); + + if (!save_hierarchical_file_table_find_path_recursive(ctx, dst_path, &new_key)) { + EPRINTF("File not found!"); + return false; + } + + if (old_key.parent != new_key.parent) { + save_hierarchical_file_table_unlink_file_from_parent(ctx, old_key.parent, file_index); + save_hierarchical_file_table_link_file_to_parent(ctx, new_key.parent, file_index); + } + + return save_fs_list_change_key(&ctx->file_table, &old_key, &new_key); +} + +static ALWAYS_INLINE bool save_is_sub_path(const char *path1, const char *path2) { + /* Check if either path is subpath of the other. */ + uint64_t path1_len = strlen(path1), path2_len = strlen(path2); + if (path1_len == 0 || path2_len == 0) + return true; + + if (path1[path1_len - 1] == '/') + path1_len--; + if (path2[path2_len - 1] == '/') + path2_len--; + + const char *short_path, *long_path; + uint64_t short_path_len, long_path_len; + if (path1_len < path2_len) { + short_path = path1; + short_path_len = path1_len; + long_path = path2; + long_path_len = path2_len; + } else { + short_path = path2; + short_path_len = path2_len; + long_path = path1; + long_path_len = path1_len; + } + + if (strncmp(short_path, long_path, short_path_len) != 0) + return false; + + return long_path_len > short_path_len + 1 && long_path[short_path_len] == '/'; +} + +bool save_hierarchical_file_table_rename_directory(hierarchical_save_file_table_ctx_t *ctx, const char *src_path, const char *dst_path) { + save_file_info_t file_info; + save_find_position_t position; + save_entry_key_t old_key, new_key; + + if (strcmp(src_path, dst_path) == 0 || save_hierarchical_file_table_try_open_file(ctx, dst_path, &file_info) || save_hierarchical_file_table_try_open_directory(ctx, dst_path, &position)) { + EPRINTF("Destination path already exists!"); + return false; + } + + if (!save_hierarchical_file_table_find_path_recursive(ctx, src_path, &old_key)) { + EPRINTF("File not found!"); + return false; + } + + uint32_t dir_index = save_fs_list_get_index_from_key(&ctx->file_table, &old_key, NULL); + + if (!save_hierarchical_file_table_find_path_recursive(ctx, dst_path, &new_key)) { + EPRINTF("File not found!"); + return false; + } + + if (save_is_sub_path(src_path, dst_path)) { + EPRINTF("Destination is subpath of source!"); + return false; + } + + if (old_key.parent != new_key.parent) { + save_hierarchical_file_table_unlink_directory_from_parent(ctx, old_key.parent, dir_index); + save_hierarchical_file_table_link_directory_to_parent(ctx, new_key.parent, dir_index); + } + + return save_fs_list_change_key(&ctx->directory_table, &old_key, &new_key); +} + +uint32_t save_hierarchical_file_table_create_parent_directory_recursive(hierarchical_save_file_table_ctx_t *ctx, path_parser_ctx_t *parser, save_entry_key_t *key) { + uint32_t prev_index = 0; + + while (!save_path_parser_is_finished(parser)) { + uint32_t index = save_fs_list_get_index_from_key(&ctx->directory_table, key, NULL); + + if (index == 0xFFFFFFFF) { + save_table_entry_t new_entry; + memset(&new_entry, 0, sizeof(new_entry)); + index = save_fs_list_add(&ctx->directory_table, key, &new_entry); + + if ((prev_index & 0x80000000) == 0) + save_hierarchical_file_table_link_directory_to_parent(ctx, prev_index, index); + } + + prev_index = index; + key->parent = index; + save_path_parser_try_get_next(parser, key->name); + } + + return prev_index; +} + +static bool save_hierarchical_file_table_create_file_recursive(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_file_info_t *file_info) { + path_parser_ctx_t parser; + if (!save_path_parser_init(&parser, path)) { + EPRINTF("Failed to init path parser!"); + return false; + } + + save_entry_key_t key = {"", 0}; + uint32_t current_len = 0; + const char *current = save_path_parser_get_current(&parser, ¤t_len); + memcpy(key.name, current, current_len); + + uint32_t parent_index = save_hierarchical_file_table_create_parent_directory_recursive(ctx, &parser, &key); + + uint32_t index = save_fs_list_get_index_from_key(&ctx->file_table, &key, NULL); + + save_table_entry_t file_entry; + memset(&file_entry, 0, sizeof(file_entry)); + + if ((index & 0x80000000) == 0) { + save_fs_list_get_value_by_index(&ctx->file_table, index, &file_entry); + memcpy(&file_entry.save_file_info, file_info, sizeof(save_file_info_t)); + save_fs_list_set_value(&ctx->file_table, index, &file_entry); + return true; + } + + memcpy(&file_entry.save_file_info, file_info, sizeof(save_file_info_t)); + index = save_fs_list_add(&ctx->file_table, &key, &file_entry); + if (index == 0) { + EPRINTF("Failed to add file to FS list!"); + return false; + } + + return save_hierarchical_file_table_link_file_to_parent(ctx, parent_index, index); +} + +static bool save_hierarchical_file_table_create_directory_recursive(hierarchical_save_file_table_ctx_t *ctx, const char *path) { + path_parser_ctx_t parser; + if (!save_path_parser_init(&parser, path)) { + EPRINTF("Failed to init path parser!"); + return false; + } + + save_entry_key_t key = {"", 0}; + uint32_t current_len = 0; + const char *current = save_path_parser_get_current(&parser, ¤t_len); + memcpy(key.name, current, current_len); + + uint32_t parent_index = save_hierarchical_file_table_create_parent_directory_recursive(ctx, &parser, &key); + + uint32_t index = save_fs_list_get_index_from_key(&ctx->directory_table, &key, NULL); + + if (index != 0xFFFFFFFF) + return true; + + save_table_entry_t dir_entry; + memset(&dir_entry, 0, sizeof(dir_entry)); + save_fs_list_add(&ctx->directory_table, &key, &dir_entry); + + return save_hierarchical_file_table_link_directory_to_parent(ctx, parent_index, index); +} + +bool save_hierarchical_file_table_add_file(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_file_info_t *file_info) { + if (strlen(path) == 1 && path[0] == '/') { + EPRINTF("Path cannot be empty!"); + return false; + } + + return save_hierarchical_file_table_create_file_recursive(ctx, path, file_info); +} + +bool save_hierarchical_file_table_add_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path) { + if (strlen(path) == 1 && path[0] == '/') { + EPRINTF("Directory path cannot be empty!"); + return false; + } + + save_hierarchical_file_table_create_directory_recursive(ctx, path); + return true; +} + diff --git a/bdk/libs/nx_savedata/hierarchical_save_file_table.h b/bdk/libs/nx_savedata/hierarchical_save_file_table.h new file mode 100644 index 0000000..15f71cd --- /dev/null +++ b/bdk/libs/nx_savedata/hierarchical_save_file_table.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _HIERARCHICAL_SAVE_FILE_TABLE_H_ +#define _HIERARCHICAL_SAVE_FILE_TABLE_H_ + +#include "save_fs_entry.h" +#include "save_fs_list.h" + +#include + +typedef struct { + save_filesystem_list_ctx_t file_table; + save_filesystem_list_ctx_t directory_table; +} hierarchical_save_file_table_ctx_t; + +bool save_hierarchical_file_table_try_open_file(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_file_info_t *file_info); +bool save_hierarchical_file_table_try_open_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_find_position_t *position); +bool save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name); +bool save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name); +bool save_hierarchical_file_table_delete_file(hierarchical_save_file_table_ctx_t *ctx, const char *path); +bool save_hierarchical_file_table_delete_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path); +bool save_hierarchical_file_table_rename_file(hierarchical_save_file_table_ctx_t *ctx, const char *src_path, const char *dst_path); +bool save_hierarchical_file_table_rename_directory(hierarchical_save_file_table_ctx_t *ctx, const char *src_path, const char *dst_path); +bool save_hierarchical_file_table_add_file(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_file_info_t *file_info); +bool save_hierarchical_file_table_add_directory(hierarchical_save_file_table_ctx_t *ctx, const char *path); + +#endif diff --git a/bdk/libs/nx_savedata/integrity_verification_storage.c b/bdk/libs/nx_savedata/integrity_verification_storage.c new file mode 100644 index 0000000..fc76501 --- /dev/null +++ b/bdk/libs/nx_savedata/integrity_verification_storage.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "integrity_verification_storage.h" + +#include +#include +#include +#include + +#include + +void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity_verification_info_ctx_t *info, substorage *hash_storage, int integrity_check_level) { + sector_storage_init(&ctx->base_storage, &info->data, info->block_size); + memcpy(&ctx->hash_storage, hash_storage, sizeof(substorage)); + ctx->integrity_check_level = integrity_check_level; + memcpy(ctx->salt, info->salt, sizeof(ctx->salt)); + ctx->block_validities = calloc(1, sizeof(validity_t) * ctx->base_storage.sector_count); +} + +/* buffer must have size count + 0x20 for salt to by copied in at offset 0. */ +static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) { + memcpy(buffer, ctx->salt, sizeof(ctx->salt)); + se_calc_sha256(out_hash, buffer, count + sizeof(ctx->salt)); + out_hash[0x1F] |= 0x80; +} + +static ALWAYS_INLINE bool is_empty(const void *buffer, uint64_t count) { + bool empty = true; + const uint8_t *buf = (const uint8_t *)buffer; + for (uint64_t i = 0; i < count; i++) { + if (buf[i] != 0) { + empty = false; + break; + } + } + return empty; +} + +bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + if (count > ctx->base_storage.sector_size) { + EPRINTF("IVFC read exceeds sector size!"); + return false; + } + + uint64_t block_index = offset / ctx->base_storage.sector_size; + + if (ctx->block_validities[block_index] == VALIDITY_INVALID && ctx->integrity_check_level) { + EPRINTF("IVFC hash error!"); + return false; + } + + uint8_t hash_buffer[0x20] = {0}; + uint64_t hash_pos = block_index * sizeof(hash_buffer); + + if (substorage_read(&ctx->hash_storage, hash_buffer, hash_pos, sizeof(hash_buffer)) != sizeof(hash_buffer)) + return false; + + if (is_empty(hash_buffer, sizeof(hash_buffer))) { + memset(buffer, 0, count); + ctx->block_validities[block_index] = VALIDITY_VALID; + return true; + } + + uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20); + if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) { + free(data_buffer); + return false; + } + + if (ctx->integrity_check_level && ctx->block_validities[block_index] != VALIDITY_UNCHECKED) { + memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count); + free(data_buffer); + return true; + } + + uint8_t hash[0x20] = {0}; + save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size); + memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count); + free(data_buffer); + + if (memcmp(hash_buffer, hash, sizeof(hash_buffer)) == 0) { + ctx->block_validities[block_index] = VALIDITY_VALID; + } else { + ctx->block_validities[block_index] = VALIDITY_INVALID; + if (ctx->integrity_check_level) { + EPRINTF("IVFC hash error!"); + return false; + } + } + + return true; +} + +bool save_ivfc_storage_write(integrity_verification_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + uint64_t block_index = offset / ctx->base_storage.sector_size; + uint64_t hash_pos = block_index * 0x20; + + uint8_t hash[0x20] = {0}; + uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20); + if (count < ctx->base_storage.sector_size) { + if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) { + free(data_buffer); + return false; + } + } + memcpy(data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), buffer, count); + + if (!is_empty(buffer, count)) { + save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size); + } + + if (substorage_write(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) { + free(data_buffer); + return false; + } + free(data_buffer); + if (substorage_write(&ctx->hash_storage, hash, hash_pos, sizeof(hash)) != sizeof(hash)) + return false; + + ctx->block_validities[block_index] = VALIDITY_UNCHECKED; + + return true; +} diff --git a/bdk/libs/nx_savedata/integrity_verification_storage.h b/bdk/libs/nx_savedata/integrity_verification_storage.h new file mode 100644 index 0000000..9765e24 --- /dev/null +++ b/bdk/libs/nx_savedata/integrity_verification_storage.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _IVFC_H_ +#define _IVFC_H_ + +#include "storage.h" + +#include + +typedef struct { + substorage hash_storage; + int integrity_check_level; + validity_t *block_validities; + uint8_t salt[0x20]; + sector_storage base_storage; +} integrity_verification_storage_ctx_t; + +typedef struct { + substorage data; + uint32_t block_size; + uint8_t salt[0x20]; +} integrity_verification_info_ctx_t; + +void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity_verification_info_ctx_t *info, substorage *hash_storage, int integrity_check_level); +bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +bool save_ivfc_storage_write(integrity_verification_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); + +#endif diff --git a/bdk/libs/nx_savedata/journal_map.c b/bdk/libs/nx_savedata/journal_map.c new file mode 100644 index 0000000..3177139 --- /dev/null +++ b/bdk/libs/nx_savedata/journal_map.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "journal_map.h" + +#include "journal_storage.h" +#include "storage.h" + +#include +#include + +static journal_map_entry_t *read_map_entries(uint8_t *map_table, uint32_t count) { + journal_map_entry_t *reader = (journal_map_entry_t *)map_table; + journal_map_entry_t *map = malloc(count * sizeof(journal_map_entry_t)); + + for (uint32_t i = 0; i < count; i++) { + map[i].virtual_index = i; + map[i].physical_index = save_journal_map_entry_get_physical_index(reader->physical_index); + reader++; + } + + return map; +} + +void save_journal_map_init(journal_map_ctx_t *ctx, journal_map_header_t *header, journal_map_params_t *map_info) { + ctx->header = header; + ctx->map_storage = map_info->map_storage; + ctx->modified_physical_blocks = map_info->physical_block_bitmap; + ctx->modified_virtual_blocks = map_info->virtual_block_bitmap; + ctx->free_blocks = map_info->free_block_bitmap; + ctx->entries = read_map_entries(ctx->map_storage, header->main_data_block_count); +} diff --git a/bdk/libs/nx_savedata/journal_map.h b/bdk/libs/nx_savedata/journal_map.h new file mode 100644 index 0000000..af37e05 --- /dev/null +++ b/bdk/libs/nx_savedata/journal_map.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _JOURNAL_MAP_H_ +#define _JOURNAL_MAP_H_ + +#include "storage.h" + +#include + +#include + +#define JOURNAL_MAP_ENTRY_SIZE 8 + +typedef struct { + uint32_t version; + uint32_t main_data_block_count; + uint32_t journal_block_count; + uint32_t _0x0C; +} journal_map_header_t; + +typedef struct { + uint8_t *map_storage; + uint8_t *physical_block_bitmap; + uint8_t *virtual_block_bitmap; + uint8_t *free_block_bitmap; +} journal_map_params_t; + +typedef struct { + uint32_t physical_index; + uint32_t virtual_index; +} journal_map_entry_t; + +typedef struct { + journal_map_header_t *header; + journal_map_entry_t *entries; + uint8_t *map_storage; + uint8_t *modified_physical_blocks; + uint8_t *modified_virtual_blocks; + uint8_t *free_blocks; +} journal_map_ctx_t; + +static ALWAYS_INLINE uint32_t save_journal_map_entry_make_physical_index(uint32_t index) { + return index | 0x80000000; +} + +static ALWAYS_INLINE uint32_t save_journal_map_entry_get_physical_index(uint32_t index) { + return index & 0x7FFFFFFF; +} + +void save_journal_map_init(journal_map_ctx_t *ctx, journal_map_header_t *header, journal_map_params_t *map_info); + +#endif diff --git a/bdk/libs/nx_savedata/journal_storage.c b/bdk/libs/nx_savedata/journal_storage.c new file mode 100644 index 0000000..434f154 --- /dev/null +++ b/bdk/libs/nx_savedata/journal_storage.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "journal_storage.h" + +#include "header.h" + +#include +#include + +#include + +void save_journal_storage_init(journal_storage_ctx_t *ctx, substorage *base_storage, journal_header_t *header, journal_map_params_t *map_info) { + memcpy(&ctx->base_storage, base_storage, sizeof(substorage)); + ctx->header = header; + save_journal_map_init(&ctx->map, &header->map_header, map_info); + ctx->block_size = (uint32_t)header->block_size; + ctx->length = header->total_size - header->journal_size; +} + +uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos; + uint32_t bytes_to_read = MIN(ctx->block_size - block_pos, remaining); + + if (substorage_read(&ctx->base_storage, (uint8_t *)buffer + out_pos, physical_offset, bytes_to_read) != bytes_to_read) + return 0; + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + } + return out_pos; +} + +uint32_t save_journal_storage_write(journal_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); + uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); + uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos; + uint32_t bytes_to_write = MIN(ctx->block_size - block_pos, remaining); + + if (substorage_write(&ctx->base_storage, (uint8_t *)buffer + out_pos, physical_offset, bytes_to_write) != bytes_to_write) + return 0; + + out_pos += bytes_to_write; + in_pos += bytes_to_write; + remaining -= bytes_to_write; + } + return out_pos; +} diff --git a/bdk/libs/nx_savedata/journal_storage.h b/bdk/libs/nx_savedata/journal_storage.h new file mode 100644 index 0000000..2c98b20 --- /dev/null +++ b/bdk/libs/nx_savedata/journal_storage.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _JOURNAL_STORAGE_H_ +#define _JOURNAL_STORAGE_H_ + +#include "hierarchical_integrity_verification_storage.h" +#include "journal_map.h" +#include "storage.h" + +#include +#include + +typedef struct { + uint32_t magic; /* JNGL */ + uint32_t version; + uint64_t total_size; + uint64_t journal_size; + uint64_t block_size; + journal_map_header_t map_header; + uint8_t reserved[0x1D0]; +} journal_header_t; + +static_assert(sizeof(journal_header_t) == 0x200, "Journal storage header size is wrong!"); + +typedef struct { + journal_map_ctx_t map; + journal_header_t *header; + uint32_t block_size; + uint64_t length; + substorage base_storage; +} journal_storage_ctx_t; + +void save_journal_storage_init(journal_storage_ctx_t *ctx, substorage *base_storage, journal_header_t *header, journal_map_params_t *map_info); +uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_journal_storage_write(journal_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); + +#endif diff --git a/bdk/libs/nx_savedata/path_parser.c b/bdk/libs/nx_savedata/path_parser.c new file mode 100644 index 0000000..afa8ee0 --- /dev/null +++ b/bdk/libs/nx_savedata/path_parser.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "path_parser.h" + +#include + +#include + +bool save_path_parser_init(path_parser_ctx_t *ctx, const char *path) { + ctx->path_len = strlen(path); + + if (ctx->path_len < 1 || path[0] != '/') { + EPRINTF("Path must begin with a '/'!"); + return false; + } + + ctx->_path = path; + ctx->_offset = 0; + ctx->_length = 0; + ctx->_finished = ctx->path_len == 1 || path[1] == '\0'; + return true; +} + +bool save_path_parser_move_next(path_parser_ctx_t *ctx) { + if (ctx->_finished) + return false; + + ctx->_offset = ctx->_offset + ctx->_length + 1; + uint32_t end = ctx->_offset; + + while (end < ctx->path_len && ctx->_path[end] != '\0' && ctx->_path[end] != '/') + end++; + + ctx->_finished = end + 1 >= ctx->path_len || ctx->_path[end + 1] == '\0'; + ctx->_length = end - ctx->_offset; + + return true; +} + +const char *save_path_parser_get_current(path_parser_ctx_t *ctx, uint32_t *out_len) { + if (out_len) + *out_len = ctx->_length; + return &ctx->_path[ctx->_offset]; +} + +bool save_path_parser_try_get_next(path_parser_ctx_t *ctx, char *name) { + bool success = save_path_parser_move_next(ctx); + uint32_t current_len = 0; + const char *current = save_path_parser_get_current(ctx, ¤t_len); + memcpy(name, current, current_len); + return success; +} diff --git a/bdk/libs/nx_savedata/path_parser.h b/bdk/libs/nx_savedata/path_parser.h new file mode 100644 index 0000000..f3637b2 --- /dev/null +++ b/bdk/libs/nx_savedata/path_parser.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _PATH_PARSER_H_ +#define _PATH_PARSER_H_ + +#include + +#include + +typedef struct { + const char *_path; + uint64_t path_len; + uint32_t _offset; + uint32_t _length; + bool _finished; +} path_parser_ctx_t; + +static ALWAYS_INLINE bool save_path_parser_is_finished(path_parser_ctx_t *ctx) { + return ctx->_finished; +} + +bool save_path_parser_init(path_parser_ctx_t *ctx, const char *path); +bool save_path_parser_move_next(path_parser_ctx_t *ctx); +const char *save_path_parser_get_current(path_parser_ctx_t *ctx, uint32_t *out_len); +bool save_path_parser_try_get_next(path_parser_ctx_t *ctx, char *name); + +#endif diff --git a/bdk/libs/nx_savedata/remap_storage.c b/bdk/libs/nx_savedata/remap_storage.c new file mode 100644 index 0000000..b00c4e1 --- /dev/null +++ b/bdk/libs/nx_savedata/remap_storage.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "remap_storage.h" + +#include "header.h" + +#include +#include +#include + +#include + +remap_segment_ctx_t *save_remap_storage_init_segments(remap_storage_ctx_t *ctx) { + remap_header_t *header = ctx->header; + remap_entry_ctx_t *map_entries = ctx->map_entries; + + remap_segment_ctx_t *segments = calloc(1, sizeof(remap_segment_ctx_t) * header->map_segment_count); + unsigned int entry_idx = 0; + + for (unsigned int i = 0; i < header->map_segment_count; i++) { + remap_segment_ctx_t *seg = &segments[i]; + seg->entry_count = 0; + remap_entry_ctx_t **ptr = malloc(sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1)); + if (!ptr) { + EPRINTF("Failed to allocate entries in remap storage!"); + return NULL; + } + seg->entries = ptr; + seg->entries[seg->entry_count++] = &map_entries[entry_idx]; + seg->offset = map_entries[entry_idx].entry.virtual_offset; + map_entries[entry_idx++].segment = seg; + + while (entry_idx < header->map_entry_count && map_entries[entry_idx - 1].ends.virtual_offset_end == map_entries[entry_idx].entry.virtual_offset) { + map_entries[entry_idx].segment = seg; + map_entries[entry_idx - 1].next = &map_entries[entry_idx]; + remap_entry_ctx_t **ptr = calloc(1, sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1)); + if (!ptr) { + EPRINTF("Failed to allocate entries in remap storage!"); + return NULL; + } + memcpy(ptr, seg->entries, sizeof(remap_entry_ctx_t *) * (seg->entry_count)); + free(seg->entries); + seg->entries = ptr; + seg->entries[seg->entry_count++] = &map_entries[entry_idx++]; + } + seg->length = seg->entries[seg->entry_count - 1]->ends.virtual_offset_end - seg->entries[0]->entry.virtual_offset; + } + return segments; +} + +static ALWAYS_INLINE remap_entry_ctx_t *save_remap_storage_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) { + uint32_t segment_idx = save_remap_get_segment_from_virtual_offset(ctx->header, offset); + if (segment_idx < ctx->header->map_segment_count) { + for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) { + if (ctx->segments[segment_idx].entries[i]->ends.virtual_offset_end > offset) { + return ctx->segments[segment_idx].entries[i]; + } + } + } + EPRINTFARGS("Remap offset %08x%08x out of range!", (uint32_t)(offset >> 32), (uint32_t)(offset & 0xFFFFFFFF)); + return NULL; +} + +uint32_t save_remap_storage_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + remap_entry_ctx_t *entry = NULL; + entry = save_remap_storage_get_map_entry(ctx, offset); + if (!entry) { + EPRINTF("Unexpected failure in remap get entry!"); + return 0; + } + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint64_t entry_pos = in_pos - entry->entry.virtual_offset; + uint32_t bytes_to_read = MIN((uint32_t)(entry->ends.virtual_offset_end - in_pos), remaining); + + if (substorage_read(&ctx->base_storage, (uint8_t *)buffer + out_pos, entry->entry.physical_offset + entry_pos, bytes_to_read) != bytes_to_read) + return 0; + + out_pos += bytes_to_read; + in_pos += bytes_to_read; + remaining -= bytes_to_read; + + if (in_pos >= entry->ends.virtual_offset_end) { + if (!entry->next && remaining) { + EPRINTF("Unexpected remap entry chain failure!"); + return 0; + } + entry = entry->next; + } + } + return out_pos; +} + +uint32_t save_remap_storage_write(remap_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + remap_entry_ctx_t *entry = NULL; + entry = save_remap_storage_get_map_entry(ctx, offset); + if (!entry) { + EPRINTF("Unexpected failure in remap get entry!"); + return 0; + } + uint64_t in_pos = offset; + uint32_t out_pos = 0; + uint32_t remaining = count; + + while (remaining) { + uint64_t entry_pos = in_pos - entry->entry.virtual_offset; + uint32_t bytes_to_write = MIN((uint32_t)(entry->ends.virtual_offset_end - in_pos), remaining); + + if (substorage_write(&ctx->base_storage, (uint8_t *)buffer + out_pos, entry->entry.physical_offset + entry_pos, bytes_to_write) != bytes_to_write) + return 0; + + out_pos += bytes_to_write; + in_pos += bytes_to_write; + remaining -= bytes_to_write; + + if (in_pos >= entry->ends.virtual_offset_end) { + if (!entry->next && remaining) { + EPRINTF("Unexpected remap entry chain failure!"); + return 0; + } + entry = entry->next; + } + } + return out_pos; +} diff --git a/bdk/libs/nx_savedata/remap_storage.h b/bdk/libs/nx_savedata/remap_storage.h new file mode 100644 index 0000000..2f67e04 --- /dev/null +++ b/bdk/libs/nx_savedata/remap_storage.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _REMAP_STORAGE_H_ +#define _REMAP_STORAGE_H_ + +#include "duplex_storage.h" +#include "storage.h" + +#include + +#define RMAP_ALIGN_SMALL 0x200 +#define RMAP_ALIGN_LARGE 0x4000 + +typedef struct { + uint32_t magic; /* RMAP */ + uint32_t version; + uint32_t map_entry_count; + uint32_t map_segment_count; + uint32_t segment_bits; + uint8_t _0x14[0x2C]; +} remap_header_t; + +typedef struct remap_segment_ctx_t remap_segment_ctx_t; +typedef struct remap_entry_ctx_t remap_entry_ctx_t; + +typedef struct { + uint64_t virtual_offset_end; + uint64_t physical_offset_end; +} remap_end_offsets_t; + +typedef struct { + uint64_t virtual_offset; + uint64_t physical_offset; + uint64_t size; + uint32_t alignment; + uint32_t _0x1C; +} remap_entry_t; + +struct remap_entry_ctx_t { + remap_entry_t entry; + remap_end_offsets_t ends; + remap_segment_ctx_t *segment; + remap_entry_ctx_t *next; +}; + +struct remap_segment_ctx_t{ + uint64_t offset; + uint64_t length; + remap_entry_ctx_t **entries; + uint64_t entry_count; +}; + +typedef struct { + remap_header_t *header; + remap_entry_ctx_t *map_entries; + remap_segment_ctx_t *segments; + substorage base_storage; +} remap_storage_ctx_t; + +static ALWAYS_INLINE uint32_t save_remap_get_segment_from_virtual_offset(remap_header_t *header, uint64_t offset) { + return (uint32_t)(offset >> (64 - header->segment_bits)); +} + +static ALWAYS_INLINE uint64_t save_remap_get_virtual_offset(remap_header_t *header, uint64_t segment) { + return segment << (64 - header->segment_bits); +} + +remap_segment_ctx_t *save_remap_storage_init_segments(remap_storage_ctx_t *ctx); +uint32_t save_remap_storage_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_remap_storage_write(remap_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); + +#endif diff --git a/bdk/libs/nx_savedata/save.c b/bdk/libs/nx_savedata/save.c new file mode 100644 index 0000000..7669e10 --- /dev/null +++ b/bdk/libs/nx_savedata/save.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "save.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void save_init_journal_ivfc_storage(save_ctx_t *ctx, hierarchical_integrity_verification_storage_ctx_t *out_ivfc, int integrity_check_level) { + const uint32_t ivfc_levels = 5; + ivfc_save_hdr_t *ivfc = &ctx->header.data_ivfc_header; + substorage levels[ivfc_levels]; + + substorage_init(&levels[0], &memory_storage_vt, ctx->data_ivfc_master, 0, ctx->header.layout.ivfc_master_hash_size); + for (unsigned int i = 0; i < ivfc_levels - 2; i++) { + ivfc_level_hdr_t *level = &ivfc->level_hash_info.level_headers[i]; + substorage_init(&levels[i + 1], &remap_storage_vt, &ctx->meta_remap_storage, fs_int64_get(&level->logical_offset), fs_int64_get(&level->hash_data_size)); + } + ivfc_level_hdr_t *data_level = &ivfc->level_hash_info.level_headers[ivfc_levels - 2]; + substorage_init(&levels[ivfc_levels - 1], &journal_storage_vt, &ctx->journal_storage, fs_int64_get(&data_level->logical_offset), fs_int64_get(&data_level->hash_data_size)); + + save_hierarchical_integrity_verification_storage_init_with_levels(out_ivfc, ivfc, ivfc_levels, levels, integrity_check_level); +} + +static void save_init_fat_ivfc_storage(save_ctx_t *ctx, hierarchical_integrity_verification_storage_ctx_t *out_ivfc, int integrity_check_level) { + substorage fat_ivfc_master; + substorage_init(&fat_ivfc_master, &memory_storage_vt, ctx->fat_ivfc_master, 0, ctx->header.layout.ivfc_master_hash_size); + save_hierarchical_integrity_verification_storage_init_for_fat(out_ivfc, &ctx->header.version_5.fat_ivfc_header, &fat_ivfc_master, &ctx->meta_remap_storage.base_storage, integrity_check_level); +} + +static validity_t save_filesystem_verify(save_ctx_t *ctx) { + validity_t journal_validity = save_hierarchical_integrity_verification_storage_validate(&ctx->core_data_ivfc_storage); + save_hierarchical_integrity_verification_storage_set_level_validities(&ctx->core_data_ivfc_storage); + + if (ctx->header.layout.version < VERSION_DISF_5) + return journal_validity; + + validity_t fat_validity = save_hierarchical_integrity_verification_storage_validate(&ctx->fat_ivfc_storage); + save_hierarchical_integrity_verification_storage_set_level_validities(&ctx->core_data_ivfc_storage); + + if (journal_validity != VALIDITY_VALID) + return journal_validity; + if (fat_validity != VALIDITY_VALID) + return fat_validity; + + return journal_validity; +} + +static bool save_process_header(save_ctx_t *ctx) { + if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS || + ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL || + ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || + ctx->header.meta_remap_header.magic != MAGIC_RMAP) + { + EPRINTF("Error: Save header is corrupt!"); + return false; + } + + ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; + ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; + + uint8_t hash[0x20]; + uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); + uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; + se_calc_sha256(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size); + ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; + + unsigned char cmac[0x10] = {}; + se_aes_key_set(10, ctx->save_mac_key, 0x10); + se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); + if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { + ctx->header_cmac_validity = VALIDITY_VALID; + } else { + ctx->header_cmac_validity = VALIDITY_INVALID; + } + + return true; +} + +void save_init(save_ctx_t *ctx, FIL *file, const uint8_t *save_mac_key, uint32_t action) { + ctx->file = file; + ctx->action = action; + memcpy(ctx->save_mac_key, save_mac_key, sizeof(ctx->save_mac_key)); +} + +bool save_process(save_ctx_t *ctx) { + substorage_init(&ctx->base_storage, &file_storage_vt, ctx->file, 0, f_size(ctx->file)); + /* Try to parse Header A. */ + if (substorage_read(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) { + EPRINTF("Failed to read save header!\n"); + return false; + } + + if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { + /* Try to parse Header B. */ + if (substorage_read(&ctx->base_storage, &ctx->header, sizeof(ctx->header), sizeof(ctx->header)) != sizeof(ctx->header)) { + EPRINTF("Failed to read save header!\n"); + return false; + } + + if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { + EPRINTF("Error: Save header is invalid!"); + return false; + } + } + + /* Initialize remap storages. */ + ctx->data_remap_storage.header = &ctx->header.main_remap_header; + ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; + + substorage_init(&ctx->data_remap_storage.base_storage, &file_storage_vt, ctx->file, ctx->header.layout.file_map_data_offset, ctx->header.layout.file_map_data_size); + ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); + uint8_t *remap_buffer = malloc(MAX(ctx->data_remap_storage.header->map_entry_count, ctx->meta_remap_storage.header->map_entry_count) * sizeof(remap_entry_t)); + if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) { + EPRINTF("Failed to read data remap table!"); + free(remap_buffer); + return false; + } + for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) { + memcpy(&ctx->data_remap_storage.map_entries[i], remap_buffer + sizeof(remap_entry_t) * i, sizeof(remap_entry_t)); + ctx->data_remap_storage.map_entries[i].ends.physical_offset_end = ctx->data_remap_storage.map_entries[i].entry.physical_offset + ctx->data_remap_storage.map_entries[i].entry.size; + ctx->data_remap_storage.map_entries[i].ends.virtual_offset_end = ctx->data_remap_storage.map_entries[i].entry.virtual_offset + ctx->data_remap_storage.map_entries[i].entry.size; + } + + /* Initialize data remap storage. */ + ctx->data_remap_storage.segments = save_remap_storage_init_segments(&ctx->data_remap_storage); + if (!ctx->data_remap_storage.segments) { + free(remap_buffer); + return false; + } + + /* Initialize hierarchical duplex storage. */ + if (!save_hierarchical_duplex_storage_init(&ctx->duplex_storage, &ctx->data_remap_storage, &ctx->header)) { + free(remap_buffer); + return false; + } + + /* Initialize meta remap storage. */ + substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length); + ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); + if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) { + EPRINTF("Failed to read meta remap table!"); + free(remap_buffer); + return false; + } + for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) { + memcpy(&ctx->meta_remap_storage.map_entries[i], remap_buffer + sizeof(remap_entry_t) * i, sizeof(remap_entry_t)); + ctx->meta_remap_storage.map_entries[i].ends.physical_offset_end = ctx->meta_remap_storage.map_entries[i].entry.physical_offset + ctx->meta_remap_storage.map_entries[i].entry.size; + ctx->meta_remap_storage.map_entries[i].ends.virtual_offset_end = ctx->meta_remap_storage.map_entries[i].entry.virtual_offset + ctx->meta_remap_storage.map_entries[i].entry.size; + } + free(remap_buffer); + + ctx->meta_remap_storage.segments = save_remap_storage_init_segments(&ctx->meta_remap_storage); + if (!ctx->meta_remap_storage.segments) + return false; + + /* Initialize journal map. */ + journal_map_params_t journal_map_info; + journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size); + if (save_remap_storage_read(&ctx->meta_remap_storage, journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size) != ctx->header.layout.journal_map_table_size) { + EPRINTF("Failed to read journal map!"); + return false; + } + + /* Initialize journal storage. */ + substorage journal_data; + substorage_init(&journal_data, &remap_storage_vt, &ctx->data_remap_storage, ctx->header.layout.journal_data_offset, ctx->header.layout.journal_data_size_b + ctx->header.layout.journal_size); + + save_journal_storage_init(&ctx->journal_storage, &journal_data, &ctx->header.journal_header, &journal_map_info); + + /* Initialize core IVFC storage. */ + save_init_journal_ivfc_storage(ctx, &ctx->core_data_ivfc_storage, ctx->action & ACTION_VERIFY); + + /* Initialize FAT storage. */ + if (ctx->header.layout.version < VERSION_DISF_5) { + ctx->fat_storage = malloc(ctx->header.layout.fat_size); + save_remap_storage_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size); + } else { + save_init_fat_ivfc_storage(ctx, &ctx->fat_ivfc_storage, ctx->action & ACTION_VERIFY); + ctx->fat_storage = malloc(ctx->fat_ivfc_storage.length); + save_remap_storage_read(&ctx->meta_remap_storage, ctx->fat_storage, fs_int64_get(&ctx->header.version_5.fat_ivfc_header.level_hash_info.level_headers[2].logical_offset), ctx->fat_ivfc_storage.length); + } + + if (ctx->action & ACTION_VERIFY) { + save_filesystem_verify(ctx); + } + + /* Initialize core save filesystem. */ + save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header); + + return true; +} + +void save_free_contexts(save_ctx_t *ctx) { + for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { + free(ctx->data_remap_storage.segments[i].entries); + } + free(ctx->data_remap_storage.segments); + for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { + free(ctx->meta_remap_storage.segments[i].entries); + } + free(ctx->meta_remap_storage.segments); + free(ctx->data_remap_storage.map_entries); + free(ctx->meta_remap_storage.map_entries); + for (unsigned int i = 0; i < 2; i++) { + free(ctx->duplex_storage.layers[i].bitmap.bitmap); + free(ctx->duplex_storage.layers[i].data_a.base_storage.ctx); + free(ctx->duplex_storage.layers[i].data_b.base_storage.ctx); + } + free(ctx->duplex_storage.layers[1].bitmap_storage.base_storage.ctx); + free(ctx->journal_storage.map.map_storage); + free(ctx->journal_storage.map.entries); + for (unsigned int i = 0; i < 4; i++) { + free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); + save_cached_storage_finalize(&ctx->core_data_ivfc_storage.levels[i + 1]); + } + free(ctx->core_data_ivfc_storage.level_validities); + if (ctx->header.layout.version >= VERSION_DISF_5) { + for (unsigned int i = 0; i < 3; i++) { + free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); + save_cached_storage_finalize(&ctx->fat_ivfc_storage.levels[i + 1]); + } + } + free(ctx->fat_ivfc_storage.level_validities); + free(ctx->fat_storage); +} + +static ALWAYS_INLINE bool save_flush(save_ctx_t *ctx) { + if (ctx->header.layout.version < VERSION_DISF_5) { + if (!save_cached_storage_flush(ctx->core_data_ivfc_storage.data_level)) { + EPRINTF("Failed to flush cached storage!"); + } + if (save_remap_storage_write(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size) != ctx->header.layout.fat_size) { + EPRINTF("Failed to write meta remap storage!"); + } + } else { + if (!save_cached_storage_flush(ctx->fat_ivfc_storage.data_level)) { + EPRINTF("Failed to flush cached storage!"); + } + if (save_remap_storage_write(&ctx->meta_remap_storage, ctx->fat_storage, fs_int64_get(&ctx->header.version_5.fat_ivfc_header.level_hash_info.level_headers[2].logical_offset), ctx->fat_ivfc_storage.length) != ctx->fat_ivfc_storage.length) { + EPRINTF("Failed to write meta remap storage!"); + } + } + return save_hierarchical_duplex_storage_flush(&ctx->duplex_storage, &ctx->data_remap_storage, &ctx->header); +} + +bool save_commit(save_ctx_t *ctx) { + if (!save_flush(ctx)) { + EPRINTF("Failed to flush save!"); + return false; + } + + uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); + uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; + uint8_t *header = (uint8_t *)&ctx->header; + se_calc_sha256(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size); + + se_aes_key_set(10, ctx->save_mac_key, 0x10); + se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); + + if (substorage_write(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) { + EPRINTF("Failed to write save header!"); + return false; + } + + return true; +} diff --git a/bdk/libs/nx_savedata/save.h b/bdk/libs/nx_savedata/save.h new file mode 100644 index 0000000..928ad56 --- /dev/null +++ b/bdk/libs/nx_savedata/save.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_H_ +#define _SAVE_H_ + +#include "header.h" +#include "hierarchical_duplex_storage.h" +#include "hierarchical_integrity_verification_storage.h" +#include "journal_map.h" +#include "journal_storage.h" +#include "remap_storage.h" +#include "save_data_file_system_core.h" +#include "storage.h" + +#include +#include + +#include +#include + +#define ACTION_VERIFY (1<<2) + +typedef struct { + save_header_t header; + FIL *file; + uint32_t action; + validity_t header_cmac_validity; + validity_t header_hash_validity; + uint8_t *data_ivfc_master; + uint8_t *fat_ivfc_master; + remap_storage_ctx_t data_remap_storage; + remap_storage_ctx_t meta_remap_storage; + hierarchical_duplex_storage_ctx_t duplex_storage; + journal_storage_ctx_t journal_storage; + hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage; + hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage; + uint8_t *fat_storage; + save_data_file_system_core_ctx_t save_filesystem_core; + substorage base_storage; + uint8_t save_mac_key[0x10]; +} save_ctx_t; + +typedef enum { + SPACE_ID_SYSTEM = 0, + SPACE_ID_USER = 1, + SPACE_ID_SD_SYSTEM = 2, + SPACE_ID_TEMP = 3, + SPACE_ID_SD_USER = 4, + SPACE_ID_PROPER_SYSTEM = 100, + SPACE_ID_SAFE_MODE = 101, +} save_data_space_id_t; + +typedef struct { + int64_t save_data_size; + int64_t journal_size; + int64_t block_size; + uint64_t owner_id; + uint32_t flags; + uint8_t space_id; + uint8_t pseudo; + uint8_t reserved[0x1A]; +} save_data_creation_info_t; + +static_assert(sizeof(save_data_creation_info_t) == 0x40, "Save data creation info size is wrong!"); + +static ALWAYS_INLINE uint32_t save_calc_map_entry_storage_size(int32_t entry_count) { + int32_t val = entry_count < 1 ? entry_count : entry_count - 1; + return (entry_count + (val >> 1)) * sizeof(remap_entry_t); +} + +void save_init(save_ctx_t *ctx, FIL *file, const uint8_t *save_mac_key, uint32_t action); +bool save_process(save_ctx_t *ctx); +bool save_create(save_ctx_t *ctx, uint32_t version, const char *mount_path, const save_data_attribute_t *attr, const save_data_creation_info_t *creation_info); +bool save_create_system_save_data(save_ctx_t *ctx, uint32_t version, const char *mount_path, uint8_t space_id, uint64_t save_id, const account_user_id_t *user_id, uint64_t owner_id, uint64_t save_data_size, uint64_t journal_size, uint32_t flags); +void save_free_contexts(save_ctx_t *ctx); +bool save_commit(save_ctx_t *ctx); + +static ALWAYS_INLINE bool save_create_directory(save_ctx_t *ctx, const char *path) { + return save_data_file_system_core_create_directory(&ctx->save_filesystem_core, path); +} + +static ALWAYS_INLINE bool save_create_file(save_ctx_t *ctx, const char *path, uint64_t size) { + return save_data_file_system_core_create_file(&ctx->save_filesystem_core, path, size); +} + +static ALWAYS_INLINE bool save_delete_directory(save_ctx_t *ctx, const char *path) { + return save_data_file_system_core_delete_directory(&ctx->save_filesystem_core,path); +} + +static ALWAYS_INLINE bool save_delete_file(save_ctx_t *ctx, const char *path) { + return save_data_file_system_core_delete_file(&ctx->save_filesystem_core, path); +} + +static ALWAYS_INLINE bool save_open_directory(save_ctx_t *ctx, save_data_directory_ctx_t *directory, const char *path, open_directory_mode_t mode) { + return save_data_file_system_core_open_directory(&ctx->save_filesystem_core, directory, path, mode); +} + +static ALWAYS_INLINE bool save_open_file(save_ctx_t *ctx, save_data_file_ctx_t *file, const char *path, open_mode_t mode) { + return save_data_file_system_core_open_file(&ctx->save_filesystem_core, file, path, mode); +} + +static ALWAYS_INLINE bool save_rename_directory(save_ctx_t *ctx, const char *old_path, const char *new_path) { + return save_data_file_system_core_rename_directory(&ctx->save_filesystem_core, old_path, new_path); +} + +static ALWAYS_INLINE bool save_rename_file(save_ctx_t *ctx, const char *old_path, const char *new_path) { + return save_data_file_system_core_rename_file(&ctx->save_filesystem_core, old_path, new_path); +} + +static ALWAYS_INLINE bool save_get_entry_type(save_ctx_t *ctx, directory_entry_type_t *out_entry_type, const char *path) { + return save_data_file_system_core_get_entry_type(&ctx->save_filesystem_core, out_entry_type, path); +} + +static ALWAYS_INLINE void save_get_free_space_size(save_ctx_t *ctx, uint64_t *out_free_space) { + return save_data_file_system_core_get_free_space_size(&ctx->save_filesystem_core, out_free_space); +} + +static ALWAYS_INLINE void save_get_total_space_size(save_ctx_t *ctx, uint64_t *out_total_size) { + return save_data_file_system_core_get_total_space_size(&ctx->save_filesystem_core, out_total_size); +} + +#endif diff --git a/bdk/libs/nx_savedata/save_data_directory.c b/bdk/libs/nx_savedata/save_data_directory.c new file mode 100644 index 0000000..2afa372 --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_directory.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "save_data_directory.h" + +#include + +void save_data_directory_init(save_data_directory_ctx_t *ctx, hierarchical_save_file_table_ctx_t *table, save_find_position_t *position, open_directory_mode_t mode) { + ctx->parent_file_table = table; + ctx->initial_position = position; + ctx->_current_position = position; + ctx->mode = mode; +} + +bool save_data_directory_read_impl(save_data_directory_ctx_t *ctx, uint64_t *out_entries_read, save_find_position_t *position, directory_entry_t *entry_buffer, uint64_t entry_count) { + hierarchical_save_file_table_ctx_t *tab = ctx->parent_file_table; + uint32_t i = 0; + save_file_info_t info; + char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; + + if (ctx->mode & OPEN_DIR_MODE_DIR) { + while ((!entry_buffer || i < entry_count) && save_hierarchical_file_table_find_next_directory(tab, position, name)) { + directory_entry_t *entry = &entry_buffer[i]; + + memcpy(entry->name, name, SAVE_FS_LIST_MAX_NAME_LENGTH); + entry->name[SAVE_FS_LIST_MAX_NAME_LENGTH] = 0; + entry->type = DIR_ENT_TYPE_DIR; + entry->size = 0; + + i++; + } + } + + if (ctx->mode & OPEN_DIR_MODE_FILE) { + while ((!entry_buffer || i < entry_count) && save_hierarchical_file_table_find_next_file(tab, position, &info, name)) { + directory_entry_t *entry = &entry_buffer[i]; + + memcpy(entry->name, name, SAVE_FS_LIST_MAX_NAME_LENGTH); + entry->name[SAVE_FS_LIST_MAX_NAME_LENGTH] = 0; + entry->type = DIR_ENT_TYPE_FILE; + entry->size = 0; + + i++; + } + } + + *out_entries_read = i; + + return true; +} + +bool save_data_directory_read(save_data_directory_ctx_t *ctx, uint64_t *out_entries_read, directory_entry_t *entry_buffer, uint64_t entry_count) { + return save_data_directory_read_impl(ctx, out_entries_read, ctx->_current_position, entry_buffer, entry_count); +} + +bool save_data_directory_get_entry_count(save_data_directory_ctx_t *ctx, uint64_t *out_entry_count) { + return save_data_directory_read_impl(ctx, out_entry_count, ctx->initial_position, NULL, 0); +} diff --git a/bdk/libs/nx_savedata/save_data_directory.h b/bdk/libs/nx_savedata/save_data_directory.h new file mode 100644 index 0000000..ee8c296 --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_directory.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_DATA_DIRECTORY_H_ +#define _SAVE_DATA_DIRECTORY_H_ + +#include "directory_entry.h" +#include "hierarchical_save_file_table.h" +#include "save_data_directory.h" +#include "save_fs_entry.h" + +#include + +typedef struct { + hierarchical_save_file_table_ctx_t *parent_file_table; + open_directory_mode_t mode; + save_find_position_t *initial_position; + save_find_position_t *_current_position; +} save_data_directory_ctx_t; + +void save_data_directory_init(save_data_directory_ctx_t *ctx, hierarchical_save_file_table_ctx_t *table, save_find_position_t *position, open_directory_mode_t mode); +bool save_data_directory_read(save_data_directory_ctx_t *ctx, uint64_t *out_entries_read, directory_entry_t *entry_buffer, uint64_t entry_count); +bool save_data_directory_get_entry_count(save_data_directory_ctx_t *ctx, uint64_t *out_entry_count); + +#endif diff --git a/bdk/libs/nx_savedata/save_data_file.c b/bdk/libs/nx_savedata/save_data_file.c new file mode 100644 index 0000000..0940052 --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_file.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "save_data_file.h" + +#include + +void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode) { + ctx->mode = mode; + memcpy(&ctx->base_storage, base_storage, sizeof(ctx->base_storage)); + ctx->path = path; + ctx->file_table = file_table; + ctx->size = size; +} + +bool save_data_file_validate_read_params(save_data_file_ctx_t *ctx, uint64_t *out_bytes_to_read, uint64_t offset, uint32_t size, open_mode_t open_mode) { + *out_bytes_to_read = 0; + + if ((open_mode & OPEN_MODE_READ) == 0) + return false; + + uint64_t file_size = ctx->size; + + if (offset > file_size) + return false; + + *out_bytes_to_read = MIN(file_size - offset, size); + + return true; +} + +bool save_data_file_validate_write_params(save_data_file_ctx_t *ctx, uint64_t offset, uint32_t size, open_mode_t open_mode, bool *out_is_resize_needed) { + *out_is_resize_needed = false; + + if ((open_mode & OPEN_MODE_WRITE) == 0) + return false; + + uint64_t file_size = ctx->size; + + if (offset + size > file_size) { + *out_is_resize_needed = true; + + if ((open_mode & OPEN_MODE_ALLOW_APPEND) == 0) + return false; + } + + return true; +} + +bool save_data_file_read(save_data_file_ctx_t *ctx, uint64_t *out_bytes_read, uint64_t offset, void *buffer, uint64_t count) { + uint64_t to_read = 0; + + if (!save_data_file_validate_read_params(ctx, &to_read, offset, count, ctx->mode)) + return false; + + if (to_read == 0) { + *out_bytes_read = 0; + return true; + } + + *out_bytes_read = save_allocation_table_storage_read(&ctx->base_storage, buffer, offset, to_read); + return true; +} + +bool save_data_file_write(save_data_file_ctx_t *ctx, uint64_t *out_bytes_written, uint64_t offset, const void *buffer, uint64_t count) { + bool is_resize_needed; + + if (!save_data_file_validate_write_params(ctx, offset, count, ctx->mode, &is_resize_needed)) + return false; + + if (is_resize_needed) { + if (!save_data_file_set_size(ctx, offset + count)) + return false; + } + + *out_bytes_written = save_allocation_table_storage_write(&ctx->base_storage, buffer, offset, count); + return true; +} + +bool save_data_file_set_size(save_data_file_ctx_t *ctx, uint64_t size) { + if (ctx->size == size) + return true; + + save_allocation_table_storage_set_size(&ctx->base_storage, size); + + save_file_info_t file_info; + if (!save_hierarchical_file_table_try_open_file(ctx->file_table, ctx->path, &file_info)) { + EPRINTF("File not found!"); + return false; + } + + file_info.start_block = ctx->base_storage.initial_block; + fs_int64_set(&file_info.length, size); + + if (!save_hierarchical_file_table_add_file(ctx->file_table, ctx->path, &file_info)) + return false; + + ctx->size = size; + + return true; +} diff --git a/bdk/libs/nx_savedata/save_data_file.h b/bdk/libs/nx_savedata/save_data_file.h new file mode 100644 index 0000000..970624c --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_file.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_DATA_FILE_H_ +#define _SAVE_DATA_FILE_H_ + +#include "allocation_table_storage.h" +#include "hierarchical_save_file_table.h" + +#include + +#include + +typedef struct { + allocation_table_storage_ctx_t base_storage; + const char *path; + hierarchical_save_file_table_ctx_t *file_table; + uint64_t size; + open_mode_t mode; +} save_data_file_ctx_t; + +static ALWAYS_INLINE void save_data_file_get_size(save_data_file_ctx_t *ctx, uint64_t *out_size) { + *out_size = ctx->size; +} + +void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode); +bool save_data_file_read(save_data_file_ctx_t *ctx, uint64_t *out_bytes_read, uint64_t offset, void *buffer, uint64_t count); +bool save_data_file_write(save_data_file_ctx_t *ctx, uint64_t *out_bytes_written, uint64_t offset, const void *buffer, uint64_t count); +bool save_data_file_set_size(save_data_file_ctx_t *ctx, uint64_t size); + +#endif \ No newline at end of file diff --git a/bdk/libs/nx_savedata/save_data_file_system_core.c b/bdk/libs/nx_savedata/save_data_file_system_core.c new file mode 100644 index 0000000..ccd3a2c --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_file_system_core.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "save_data_file_system_core.h" + +#include "allocation_table_storage.h" +#include "header.h" +#include "save.h" + +#include +#include + +static ALWAYS_INLINE void save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { + save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index); +} + +void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) { + save_allocation_table_init(&ctx->allocation_table, allocation_table, &save_fs_header->fat_header); + ctx->header = save_fs_header; + ctx->base_storage = storage; + + save_filesystem_list_ctx_t *dir_table = &ctx->file_table.directory_table; + save_filesystem_list_ctx_t *file_table = &ctx->file_table.file_table; + save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block); + save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block); + save_fs_list_init(dir_table); + save_fs_list_init(file_table); +} + +bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path) { + return save_hierarchical_file_table_add_directory(&ctx->file_table, path); +} + +bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size) { + if (size == 0) { + save_file_info_t empty_file_entry = {0x80000000, {0}, {0}}; + save_hierarchical_file_table_add_file(&ctx->file_table, path, &empty_file_entry); + return true; + } + + uint32_t block_count = (uint32_t)DIV_ROUND_UP(size, ctx->allocation_table.header->block_size); + uint32_t start_block = save_allocation_table_allocate(&ctx->allocation_table, block_count); + + if (start_block == 0xFFFFFFFF) + return false; + + save_file_info_t file_entry = {start_block, {0}, {0}}; + fs_int64_set(&file_entry.length, size); + return save_hierarchical_file_table_add_file(&ctx->file_table, path, &file_entry); +} + +bool save_data_file_system_core_delete_directory(save_data_file_system_core_ctx_t *ctx, const char *path) { + return save_hierarchical_file_table_delete_directory(&ctx->file_table, path); +} + +bool save_data_file_system_core_delete_file(save_data_file_system_core_ctx_t *ctx, const char *path) { + save_file_info_t file_info; + if (!save_hierarchical_file_table_try_open_file(&ctx->file_table, path, &file_info)) + return false; + + if (file_info.start_block != 0x80000000) { + save_allocation_table_free(&ctx->allocation_table, file_info.start_block); + } + + save_hierarchical_file_table_delete_file(&ctx->file_table, path); + + return true; +} + +bool save_data_file_system_core_open_directory(save_data_file_system_core_ctx_t *ctx, save_data_directory_ctx_t *directory, const char *path, open_directory_mode_t mode) { + memset(directory, 0, sizeof(save_data_directory_ctx_t)); + + save_find_position_t position; + if (!save_hierarchical_file_table_try_open_directory(&ctx->file_table, path, &position)) + return false; + + save_data_directory_init(directory, &ctx->file_table, &position, mode); + + return true; +} + +bool save_data_file_system_core_open_file(save_data_file_system_core_ctx_t *ctx, save_data_file_ctx_t *file, const char *path, open_mode_t mode) { + memset(file, 0, sizeof(save_data_file_ctx_t)); + + save_file_info_t file_info; + if (!save_hierarchical_file_table_try_open_file(&ctx->file_table, path, &file_info)) + return false; + + allocation_table_storage_ctx_t storage; + save_data_file_system_core_open_fat_storage(ctx, &storage, file_info.start_block); + + save_data_file_init(file, &storage, path, &ctx->file_table, fs_int64_get(&file_info.length), mode); + + return true; +} + +bool save_data_file_system_core_get_entry_type(save_data_file_system_core_ctx_t *ctx, directory_entry_type_t *out_entry_type, const char *path) { + save_file_info_t info; + if (save_hierarchical_file_table_try_open_file(&ctx->file_table, path, &info)) { + *out_entry_type = DIR_ENT_TYPE_FILE; + return true; + } + + save_find_position_t position; + if (save_hierarchical_file_table_try_open_directory(&ctx->file_table, path, &position)) { + *out_entry_type = DIR_ENT_TYPE_DIR; + return true; + } + + return false; +} diff --git a/bdk/libs/nx_savedata/save_data_file_system_core.h b/bdk/libs/nx_savedata/save_data_file_system_core.h new file mode 100644 index 0000000..14c4523 --- /dev/null +++ b/bdk/libs/nx_savedata/save_data_file_system_core.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_DATA_FILE_SYSTEM_CORE_H_ +#define _SAVE_DATA_FILE_SYSTEM_CORE_H_ + +#include "allocation_table.h" +#include "header.h" +#include "hierarchical_save_file_table.h" +#include "save_data_directory.h" +#include "save_data_file.h" +#include "storage.h" + +typedef struct { + substorage *base_storage; + allocation_table_ctx_t allocation_table; + save_fs_header_t *header; + hierarchical_save_file_table_ctx_t file_table; +} save_data_file_system_core_ctx_t; + +static ALWAYS_INLINE bool save_data_file_system_core_rename_directory(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) { + return save_hierarchical_file_table_rename_directory(&ctx->file_table, old_path, new_path); +} + +static ALWAYS_INLINE bool save_data_file_system_core_rename_file(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) { + return save_hierarchical_file_table_rename_file(&ctx->file_table, old_path, new_path); +} + +static ALWAYS_INLINE void save_data_file_system_core_get_free_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_free_space) { + uint32_t free_block_count = save_allocation_table_get_free_list_length(&ctx->allocation_table); + *out_free_space = ctx->header->block_size * free_block_count; +} + +static ALWAYS_INLINE void save_data_file_system_core_get_total_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_total_space) { + *out_total_space = ctx->header->block_size * ctx->header->block_count; +} + +void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header); + +bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path); +bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size); +bool save_data_file_system_core_delete_directory(save_data_file_system_core_ctx_t *ctx, const char *path); +bool save_data_file_system_core_delete_file(save_data_file_system_core_ctx_t *ctx, const char *path); +bool save_data_file_system_core_open_directory(save_data_file_system_core_ctx_t *ctx, save_data_directory_ctx_t *directory, const char *path, open_directory_mode_t mode); +bool save_data_file_system_core_open_file(save_data_file_system_core_ctx_t *ctx, save_data_file_ctx_t *file, const char *path, open_mode_t mode); +bool save_data_file_system_core_get_entry_type(save_data_file_system_core_ctx_t *ctx, directory_entry_type_t *out_entry_type, const char *path); + +#endif diff --git a/bdk/libs/nx_savedata/save_fs_entry.h b/bdk/libs/nx_savedata/save_fs_entry.h new file mode 100644 index 0000000..8f49944 --- /dev/null +++ b/bdk/libs/nx_savedata/save_fs_entry.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_FS_ENTRY_H_ +#define _SAVE_FS_ENTRY_H_ + +#include "fs_int64.h" + +#include +#include + +typedef struct { + char name[0x40]; + uint32_t parent; +} save_entry_key_t; + +static_assert(sizeof(save_entry_key_t) == 0x44, "Save entry key size is wrong!"); + +typedef struct { + uint32_t start_block; + fs_int64_t length; + uint32_t _0xC[2]; +} save_file_info_t; + +static_assert(sizeof(save_file_info_t) == 0x14, "Save file info size is wrong!"); + +typedef struct { + uint32_t next_directory; + uint32_t next_file; + uint32_t _0x8[3]; +} save_find_position_t; + +static_assert(sizeof(save_find_position_t) == 0x14, "Save find position size is wrong!"); + +#endif diff --git a/bdk/libs/nx_savedata/save_fs_list.c b/bdk/libs/nx_savedata/save_fs_list.c new file mode 100644 index 0000000..78e2abe --- /dev/null +++ b/bdk/libs/nx_savedata/save_fs_list.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "save_fs_list.h" + +#include + +#include + +void save_fs_list_init(save_filesystem_list_ctx_t *ctx) { + ctx->free_list_head_index = 0; + ctx->used_list_head_index = 1; +} + +static ALWAYS_INLINE uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) { + uint32_t capacity; + if (save_allocation_table_storage_read(&ctx->storage, &capacity, 4, 4) != 4) { + EPRINTF("Failed to read FS list capacity!"); + return 0; + } + return capacity; +} + +static ALWAYS_INLINE uint32_t save_fs_list_get_length(save_filesystem_list_ctx_t *ctx) { + uint32_t length; + if (save_allocation_table_storage_read(&ctx->storage, &length, 0, 4) != 4) { + EPRINTF("Failed to read FS list length!"); + return 0; + } + return length; +} + +static ALWAYS_INLINE bool save_fs_list_set_capacity(save_filesystem_list_ctx_t *ctx, uint32_t capacity) { + return save_allocation_table_storage_write(&ctx->storage, &capacity, 4, 4) == 4; +} + +static ALWAYS_INLINE bool save_fs_list_set_length(save_filesystem_list_ctx_t *ctx, uint32_t length) { + return save_allocation_table_storage_write(&ctx->storage, &length, 0, 4) == 4; +} + +uint32_t save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key, uint32_t *prev_index) { + save_fs_list_entry_t entry; + uint32_t capacity = save_fs_list_get_capacity(ctx); + if (save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) { + EPRINTF("Failed to read used list head entry!"); + return 0xFFFFFFFF; + } + uint32_t prev; + if (!prev_index) { + prev_index = &prev; + } + *prev_index = ctx->used_list_head_index; + uint32_t index = entry.next; + while (index) { + if (index > capacity) { + EPRINTFARGS("Save entry index %d out of range!", index); + return 0xFFFFFFFF; + } + if (save_fs_list_read_entry(ctx, index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) + return 0xFFFFFFFF; + if (entry.parent == key->parent && !strcmp(entry.name, key->name)) { + return index; + } + *prev_index = index; + index = entry.next; + } + *prev_index = 0xFFFFFFFF; + return 0xFFFFFFFF; +} + +bool save_fs_list_get_value_by_index(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value) { + save_fs_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + if (save_fs_list_read_entry(ctx, index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) { + EPRINTFARGS("Failed to read FS list entry at index %x!", index); + return false; + } + memcpy(value, &entry.value, sizeof(save_table_entry_t)); + return true; +} + +bool save_fs_list_get_value_and_name(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value, char *name) { + save_fs_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + if (save_fs_list_read_entry(ctx, index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) { + EPRINTFARGS("Failed to read FS list entry at index %x!", index); + return false; + } + memcpy(value, &entry.value, sizeof(save_table_entry_t)); + memcpy(name, entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); + return true; +} + +bool save_fs_list_try_get_value_by_index(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value) { + if ((index & 0x80000000) != 0 || index >= save_fs_list_get_capacity(ctx)) { + memset(value, 0, sizeof(save_table_entry_t)); + return false; + } + + return save_fs_list_get_value_by_index(ctx, index, value); +} + +bool save_fs_list_try_get_value_by_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, save_table_entry_t *value) { + uint32_t index = save_fs_list_get_index_from_key(ctx, key, NULL); + + if ((index & 0x80000000) != 0) { + memset(value, 0, sizeof(save_table_entry_t)); + return false; + } + + return save_fs_list_try_get_value_by_index(ctx, index, value); +} + +bool save_fs_list_try_get_value_and_name(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value, char *name) { + if ((index & 0x80000000) != 0 || index >= save_fs_list_get_capacity(ctx)) { + memset(value, 0, sizeof(save_table_entry_t)); + return false; + } + + return save_fs_list_get_value_and_name(ctx, index, value, name); +} + +bool save_fs_list_set_value(save_filesystem_list_ctx_t *ctx, uint32_t index, const save_table_entry_t *value) { + save_fs_list_entry_t entry = {0}; + if (save_fs_list_read_entry(ctx, index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + memcpy(&entry.value, value, sizeof(save_table_entry_t)); + return save_fs_list_write_entry(ctx, index, &entry) == SAVE_FS_LIST_ENTRY_SIZE; +} + +bool save_fs_list_free(save_filesystem_list_ctx_t *ctx, uint32_t entry_index) { + save_fs_list_entry_t free_entry, entry; + if (save_fs_list_read_entry(ctx, ctx->free_list_head_index, &free_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + if (save_fs_list_read_entry(ctx, entry_index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + + entry.next = free_entry.next; + free_entry.next = entry_index; + + if (save_fs_list_write_entry(ctx, ctx->free_list_head_index, &free_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + return save_fs_list_write_entry(ctx, entry_index, &entry) == SAVE_FS_LIST_ENTRY_SIZE; +} + +bool save_fs_list_remove(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key) { + uint32_t index, previous_index; + index = save_fs_list_get_index_from_key(ctx, key, &previous_index); + if (index == 0xFFFFFFFF) + return false; + + save_fs_list_entry_t prev_entry, entry_to_del; + if (save_fs_list_read_entry(ctx, previous_index, &prev_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + if (save_fs_list_read_entry(ctx, index, &entry_to_del) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + + prev_entry.next = entry_to_del.next; + if (save_fs_list_write_entry(ctx, previous_index, &prev_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + + return save_fs_list_free(ctx, index); +} + +bool save_fs_list_change_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *old_key, save_entry_key_t *new_key) { + uint32_t index = save_fs_list_get_index_from_key(ctx, old_key, NULL); + uint32_t new_index = save_fs_list_get_index_from_key(ctx, new_key, NULL); + + if (index == 0xFFFFFFFF) { + EPRINTF("Old key was not found!"); + return false; + } + if (new_index != 0xFFFFFFFF) { + EPRINTF("New key already exists!"); + return false; + } + + save_fs_list_entry_t entry; + if (save_fs_list_read_entry(ctx, index, &entry) != SAVE_FS_LIST_ENTRY_SIZE) + return false; + + entry.parent = new_key->parent; + memcpy(entry.name, new_key->name, SAVE_FS_LIST_MAX_NAME_LENGTH); + + return save_fs_list_write_entry(ctx, index, &entry) == SAVE_FS_LIST_ENTRY_SIZE; +} + +uint32_t save_fs_list_allocate_entry(save_filesystem_list_ctx_t *ctx) { + save_fs_list_entry_t free_list_head, used_list_head; + if (save_fs_list_read_entry(ctx, ctx->free_list_head_index, &free_list_head) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + if (save_fs_list_read_entry(ctx, ctx->used_list_head_index, &used_list_head) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + + uint32_t allocated_index = free_list_head.next; + + if (allocated_index != 0) { + save_fs_list_entry_t first_free_entry; + if (save_fs_list_read_entry(ctx, allocated_index, &first_free_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + + free_list_head.next = first_free_entry.next; + first_free_entry.next = used_list_head.next; + used_list_head.next = allocated_index; + + if (save_fs_list_write_entry(ctx, ctx->free_list_head_index, &free_list_head) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + if (save_fs_list_write_entry(ctx, ctx->used_list_head_index, &used_list_head) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + if (save_fs_list_write_entry(ctx, allocated_index, &first_free_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + + return allocated_index; + } + + uint32_t length = save_fs_list_get_length(ctx); + uint32_t capacity = save_fs_list_get_capacity(ctx); + + if (capacity == 0 || length >= capacity) { + uint64_t current_size, new_size; + save_allocation_table_storage_get_size(&ctx->storage, ¤t_size); + if (!save_allocation_table_storage_set_size(&ctx->storage, current_size + 0x4000)) + return 0; + save_allocation_table_storage_get_size(&ctx->storage, &new_size); + if (!save_fs_list_set_capacity(ctx, (uint32_t)(new_size / sizeof(save_fs_list_entry_t)))) + return 0; + } + + if (!save_fs_list_set_length(ctx, length + 1)) + return 0; + + save_fs_list_entry_t new_entry; + if (save_fs_list_read_entry(ctx, length, &new_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + + new_entry.next = used_list_head.next; + used_list_head.next = length; + + if (save_fs_list_write_entry(ctx, ctx->used_list_head_index, &used_list_head) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + if (save_fs_list_write_entry(ctx, length, &new_entry) != SAVE_FS_LIST_ENTRY_SIZE) + return 0; + + return length; +} + +uint32_t save_fs_list_add(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key, const save_table_entry_t *value) { + uint32_t index = save_fs_list_get_index_from_key(ctx, key, NULL); + + if (index != 0xFFFFFFFF) { + save_fs_list_set_value(ctx, index, value); + return index; + } + + index = save_fs_list_allocate_entry(ctx); + if (index == 0) { + EPRINTF("Failed to allocate FS list entry!"); + return 0; + } + + save_fs_list_entry_t entry; + save_fs_list_read_entry(ctx, index, &entry); + memcpy(&entry.value, value, sizeof(save_table_entry_t)); + entry.parent = key->parent; + memcpy(entry.name, key->name, SAVE_FS_LIST_MAX_NAME_LENGTH); + save_fs_list_write_entry(ctx, index, &entry); + + return index; +} diff --git a/bdk/libs/nx_savedata/save_fs_list.h b/bdk/libs/nx_savedata/save_fs_list.h new file mode 100644 index 0000000..72b4e4b --- /dev/null +++ b/bdk/libs/nx_savedata/save_fs_list.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _SAVE_FS_LIST_H_ +#define _SAVE_FS_LIST_H_ + +#include "allocation_table_storage.h" +#include "save_fs_entry.h" + +#include +#include + +#define SAVE_FS_LIST_ENTRY_SIZE 0x60 +#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40 + +typedef struct { + uint32_t free_list_head_index; + uint32_t used_list_head_index; + allocation_table_storage_ctx_t storage; +} save_filesystem_list_ctx_t; + +typedef struct { + uint32_t next_sibling; + union { /* Save table entry type. Size = 0x14. */ + save_file_info_t save_file_info; + save_find_position_t save_find_position; + }; +} save_table_entry_t; + +static_assert(sizeof(save_table_entry_t) == 0x18, "Save table entry size is wrong!"); + +typedef struct { + uint32_t parent; + char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; + save_table_entry_t value; + uint32_t next; +} save_fs_list_entry_t; + +typedef struct { + uint32_t list_size; + uint32_t list_capacity; + uint8_t rsvd[0x54]; + uint32_t next; +} save_fs_list_entry_meta_t; + +static_assert(sizeof(save_fs_list_entry_t) == 0x60, "Save filesystem list entry size is wrong!"); + +static ALWAYS_INLINE uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, void *entry) { + return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); +} + +static ALWAYS_INLINE uint32_t save_fs_list_write_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, const void *entry) { + return save_allocation_table_storage_write(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); +} + +void save_fs_list_init(save_filesystem_list_ctx_t *ctx); +uint32_t save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key, uint32_t *prev_index); +bool save_fs_list_get_value_by_index(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value); +bool save_fs_list_get_value_and_name(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value, char *name); +bool save_fs_list_try_get_value_by_index(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value); +bool save_fs_list_try_get_value_by_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, save_table_entry_t *value); +bool save_fs_list_try_get_value_and_name(save_filesystem_list_ctx_t *ctx, uint32_t index, save_table_entry_t *value, char *name); +bool save_fs_list_set_value(save_filesystem_list_ctx_t *ctx, uint32_t index, const save_table_entry_t *value); +bool save_fs_list_remove(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key); +bool save_fs_list_change_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *old_key, save_entry_key_t *new_key); +uint32_t save_fs_list_add(save_filesystem_list_ctx_t *ctx, const save_entry_key_t *key, const save_table_entry_t *value); + +#endif diff --git a/bdk/libs/nx_savedata/storage.c b/bdk/libs/nx_savedata/storage.c new file mode 100644 index 0000000..326f051 --- /dev/null +++ b/bdk/libs/nx_savedata/storage.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "storage.h" + +#include "cached_storage.h" +#include "hierarchical_duplex_storage.h" +#include "hierarchical_integrity_verification_storage.h" +#include "journal_storage.h" +#include "remap_storage.h" + +#include +#include + +#include + +void storage_init(storage *this, const storage_vt *vt, void *ctx) { + this->vt = vt; + this->ctx = ctx; +} + +void substorage_init(substorage *this, const storage_vt *vt, void *ctx, uint64_t offset, uint64_t length) { + storage_init(&this->base_storage, vt, ctx); + this->offset = offset; + this->length = length; +} + +bool substorage_init_from_other(substorage *this, const substorage *other, uint64_t offset, uint64_t length) { + if (offset + length > other->length) { + EPRINTF("Invalid size for substorage init!"); + EPRINTFARGS("ofs %x len %x size %x", (uint32_t)offset, (uint32_t)length, (uint32_t)other->length); + return false; + } + substorage_init(this, other->base_storage.vt, other->base_storage.ctx, other->offset + offset, length); + return true; +} + +void sector_storage_init(sector_storage *ctx, substorage *base_storage, uint32_t sector_size) { + memcpy(&ctx->base_storage, base_storage, sizeof(substorage)); + ctx->sector_size = sector_size; + ctx->length = base_storage->length; + ctx->sector_count = (uint32_t)(DIV_ROUND_UP(ctx->length, ctx->sector_size)); +} + +uint32_t sector_storage_read(sector_storage *ctx, void *buffer, uint64_t offset, uint64_t count) { + uint64_t remaining = count; + uint64_t in_offset = offset; + uint32_t out_offset = 0; + uint32_t sector_size = ctx->sector_size; + + while (remaining) { + uint32_t sector_pos = (uint32_t)(in_offset % sector_size); + uint32_t bytes_to_read = MIN((uint32_t)remaining, (uint32_t)(sector_size - sector_pos)); + + substorage_read(&ctx->base_storage, (uint8_t *)buffer + out_offset, in_offset, bytes_to_read); + + out_offset += bytes_to_read; + in_offset += bytes_to_read; + remaining -= bytes_to_read; + } + + return out_offset; +} + +uint32_t sector_storage_write(sector_storage *ctx, const void *buffer, uint64_t offset, uint64_t count) { + uint64_t remaining = count; + uint64_t in_offset = offset; + uint32_t out_offset = 0; + uint32_t sector_size = ctx->sector_size; + + while (remaining) { + uint32_t sector_pos = (uint32_t)(in_offset % sector_size); + uint32_t bytes_to_write = MIN((uint32_t)remaining, (uint32_t)(sector_size - sector_pos)); + + substorage_write(&ctx->base_storage, (uint8_t *)buffer + out_offset, in_offset, bytes_to_write); + + out_offset += bytes_to_write; + in_offset += bytes_to_write; + remaining -= bytes_to_write; + } + + return out_offset; +} + +uint32_t save_hierarchical_integrity_verification_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + hierarchical_integrity_verification_storage_ctx_t *storage = (hierarchical_integrity_verification_storage_ctx_t *)ctx; + return save_cached_storage_read(storage->data_level, buffer, offset, count); +} + +uint32_t save_hierarchical_integrity_verification_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + hierarchical_integrity_verification_storage_ctx_t *storage = (hierarchical_integrity_verification_storage_ctx_t *)ctx; + return save_cached_storage_write(storage->data_level, buffer, offset, count); +} + +void save_hierarchical_integrity_verification_storage_get_size_wrapper(void *ctx, uint64_t *out_size) { + hierarchical_integrity_verification_storage_ctx_t *storage = (hierarchical_integrity_verification_storage_ctx_t *)ctx; + *out_size = storage->length; +} + +uint32_t memory_storage_read(uint8_t *storage, void *buffer, uint64_t offset, uint64_t count) { + memcpy(buffer, storage + offset, count); + return count; +} + +uint32_t memory_storage_write(uint8_t *storage, const void *buffer, uint64_t offset, uint64_t count) { + memcpy(storage + offset, buffer, count); + return count; +} + +uint32_t memory_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return memory_storage_read((uint8_t *)ctx, buffer, offset, count); +} + +uint32_t memory_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return memory_storage_write((uint8_t *)ctx, buffer, offset, count); +} + +uint32_t save_file_read(FIL *fp, void *buffer, uint64_t offset, uint64_t count) { + UINT bytes_read = 0; + + if (f_lseek(fp, offset) || f_read(fp, buffer, count, &bytes_read) || bytes_read != count) { + EPRINTFARGS("Failed to read file at offset %x!\nRead %x bytes. Req %x bytes.", (uint32_t)offset, bytes_read, (uint32_t)count); + return 0; + } + return bytes_read; +} + +uint32_t save_file_write(FIL *fp, const void *buffer, uint64_t offset, uint64_t count) { + UINT bytes_written = 0; + if (f_lseek(fp, offset) || f_write(fp, buffer, count, &bytes_written) || bytes_written != count) { + EPRINTFARGS("Failed to write file at offset %x!", (uint32_t)offset); + return 0; + } + return bytes_written; +} + +void save_file_get_size(FIL *fp, uint64_t *out_size) { + *out_size = f_size(fp); +} + +uint32_t save_file_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_file_read((FIL *)ctx, buffer, offset, count); +} + +uint32_t save_file_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_file_write((FIL *)ctx, buffer, offset, count); +} + +void save_file_get_size_wrapper(void *ctx, uint64_t *out_size) { + save_file_get_size((FIL *)ctx, out_size); +} + +uint32_t save_remap_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_remap_storage_read((remap_storage_ctx_t *)ctx, buffer, offset, count); +} + +uint32_t save_remap_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_remap_storage_write((remap_storage_ctx_t *)ctx, buffer, offset, count); +} + +void save_remap_storage_get_size_wrapper(__attribute__((unused)) void *ctx, uint64_t *out_size) { + *out_size = -1; +} + +uint32_t save_journal_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_journal_storage_read((journal_storage_ctx_t *)ctx, buffer, offset, count); +} + +uint32_t save_journal_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_journal_storage_write((journal_storage_ctx_t *)ctx, buffer, offset, count); +} + +void save_journal_storage_get_size_wrapper(void *ctx, uint64_t *out_size) { + journal_storage_ctx_t *journal = (journal_storage_ctx_t *)ctx; + *out_size = journal->length; +} + +uint32_t save_ivfc_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_ivfc_storage_read((integrity_verification_storage_ctx_t *)ctx, buffer, offset, count) ? count : 0; +} + +uint32_t save_ivfc_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_ivfc_storage_write((integrity_verification_storage_ctx_t *)ctx, buffer, offset, count) ? count : 0; +} + +void save_ivfc_storage_get_size_wrapper(void *ctx, uint64_t *out_size) { + integrity_verification_storage_ctx_t *ivfc = (integrity_verification_storage_ctx_t *)ctx; + *out_size = ivfc->base_storage.length; +} + +uint32_t save_hierarchical_duplex_storage_read(hierarchical_duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_duplex_storage_read(ctx->data_layer, buffer, offset, count); +} + +uint32_t save_hierarchical_duplex_storage_write(hierarchical_duplex_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_duplex_storage_write(ctx->data_layer, buffer, offset, count); +} + +uint32_t save_hierarchical_duplex_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count) { + return save_hierarchical_duplex_storage_read((hierarchical_duplex_storage_ctx_t *)ctx, buffer, offset, count); +} + +uint32_t save_hierarchical_duplex_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return save_hierarchical_duplex_storage_write((hierarchical_duplex_storage_ctx_t *)ctx, buffer, offset, count); +} + +void save_hierarchical_duplex_storage_get_size_wrapper(void *ctx, uint64_t *out_size) { + hierarchical_duplex_storage_ctx_t *duplex = (hierarchical_duplex_storage_ctx_t *)ctx; + *out_size = duplex->_length; +} diff --git a/bdk/libs/nx_savedata/storage.h b/bdk/libs/nx_savedata/storage.h new file mode 100644 index 0000000..545a26b --- /dev/null +++ b/bdk/libs/nx_savedata/storage.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019-2020 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +ISC License + +hactool Copyright (c) 2018, SciresM + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef HACTOOL_STORAGE_H +#define HACTOOL_STORAGE_H + +#include + +#include + +typedef struct { + uint32_t (*read)(void *ctx, void *buffer, uint64_t offset, uint64_t count); + uint32_t (*write)(void *ctx, const void *buffer, uint64_t offset, uint64_t count); + void (*set_size)(void *ctx, uint64_t size); + void (*get_size)(void *ctx, uint64_t *out_size); +} storage_vt; + +typedef struct { + const storage_vt *vt; + void *ctx; +} storage; + +void storage_init(storage *this, const storage_vt *vt, void *ctx); + +typedef struct { + uint64_t offset; + uint64_t length; + storage base_storage; +} substorage; + +void substorage_init(substorage *this, const storage_vt *vt, void *ctx, uint64_t offset, uint64_t length); +bool substorage_init_from_other(substorage *this, const substorage *other, uint64_t offset, uint64_t length); + +static ALWAYS_INLINE uint32_t substorage_read(substorage *ctx, void *buffer, uint64_t offset, uint64_t count) { + return ctx->base_storage.vt->read(ctx->base_storage.ctx, buffer, ctx->offset + offset, count); +} + +static ALWAYS_INLINE uint32_t substorage_write(substorage *ctx, const void *buffer, uint64_t offset, uint64_t count) { + return ctx->base_storage.vt->write(ctx->base_storage.ctx, buffer, ctx->offset + offset, count); +} + +static ALWAYS_INLINE void substorage_get_size(substorage *ctx, uint64_t *out_size) { + ctx->base_storage.vt->get_size(ctx->base_storage.ctx, out_size); +} + +typedef struct { + substorage base_storage; + uint32_t sector_size; + uint32_t sector_count; + uint64_t length; +} sector_storage; + +void sector_storage_init(sector_storage *ctx, substorage *base_storage, uint32_t sector_size); + +uint32_t save_hierarchical_integrity_verification_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_hierarchical_integrity_verification_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_hierarchical_integrity_verification_storage_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt hierarchical_integrity_verification_storage_vt = { + save_hierarchical_integrity_verification_storage_read_wrapper, + save_hierarchical_integrity_verification_storage_write_wrapper, + NULL, + save_hierarchical_integrity_verification_storage_get_size_wrapper +}; + +uint32_t memory_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t memory_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); + +static const storage_vt memory_storage_vt = { + memory_storage_read_wrapper, + memory_storage_write_wrapper, + NULL, + NULL +}; + +uint32_t save_file_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_file_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_file_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt file_storage_vt = { + save_file_read_wrapper, + save_file_write_wrapper, + NULL, + save_file_get_size_wrapper +}; + +uint32_t save_remap_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_remap_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_remap_storage_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt remap_storage_vt = { + save_remap_storage_read_wrapper, + save_remap_storage_write_wrapper, + NULL, + save_remap_storage_get_size_wrapper +}; + +uint32_t save_journal_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_journal_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_journal_storage_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt journal_storage_vt = { + save_journal_storage_read_wrapper, + save_journal_storage_write_wrapper, + NULL, + save_journal_storage_get_size_wrapper +}; + +uint32_t save_ivfc_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_ivfc_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_ivfc_storage_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt ivfc_storage_vt = { + save_ivfc_storage_read_wrapper, + save_ivfc_storage_write_wrapper, + NULL, + save_ivfc_storage_get_size_wrapper +}; + +uint32_t save_hierarchical_duplex_storage_read_wrapper(void *ctx, void *buffer, uint64_t offset, uint64_t count); +uint32_t save_hierarchical_duplex_storage_write_wrapper(void *ctx, const void *buffer, uint64_t offset, uint64_t count); +void save_hierarchical_duplex_storage_get_size_wrapper(void *ctx, uint64_t *out_size); + +static const storage_vt hierarchical_duplex_storage_vt = { + save_hierarchical_duplex_storage_read_wrapper, + save_hierarchical_duplex_storage_write_wrapper, + NULL, + save_hierarchical_duplex_storage_get_size_wrapper +}; + +static ALWAYS_INLINE bool is_range_valid(uint64_t offset, uint64_t size, uint64_t total_size) { + return offset >= 0 && + size >= 0 && + size <= total_size && + offset <= total_size - size; +} + +#endif diff --git a/source/keys/save.c b/source/keys/save.c deleted file mode 100644 index 463bb95..0000000 --- a/source/keys/save.c +++ /dev/null @@ -1,829 +0,0 @@ -#include -#include -#include "save.h" - -#include -#include -#include -#include -#include - -#define REMAP_ENTRY_LENGTH 0x20 - -static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) { - *((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7); -} - -static inline void save_bitmap_clear_bit(void *buffer, size_t bit_offset) { - *((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7)); -} - -static inline uint8_t save_bitmap_check_bit(const void *buffer, size_t bit_offset) { - return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7)); -} - -void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size) { - ctx->data_a = layer->data_a; - ctx->data_b = layer->data_b; - ctx->bitmap_storage = (uint8_t *)bitmap; - ctx->block_size = 1 << layer->info.block_size_power; - - ctx->bitmap.data = ctx->bitmap_storage; - ctx->bitmap.bitmap = malloc(bitmap_size >> 3); - - uint32_t bits_remaining = bitmap_size; - uint32_t bitmap_pos = 0; - uint32_t *buffer_pos = (uint32_t *)bitmap; - while (bits_remaining) { - uint32_t bits_to_read = bits_remaining < 32 ? bits_remaining : 32; - uint32_t val = *buffer_pos; - for (uint32_t i = 0; i < bits_to_read; i++) { - if (val & 0x80000000) - save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos); - else - save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos); - bitmap_pos++; - bits_remaining--; - val <<= 1; - } - buffer_pos++; - } -} - -uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); - uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; - - uint8_t *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? ctx->data_b : ctx->data_a; - memcpy((uint8_t *)buffer + out_pos, data + in_pos, bytes_to_read); - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) { - remap_segment_ctx_t *segments = calloc(1, sizeof(remap_segment_ctx_t) * header->map_segment_count); - unsigned int entry_idx = 0; - - for (unsigned int i = 0; i < header->map_segment_count; i++) { - remap_segment_ctx_t *seg = &segments[i]; - seg->entry_count = 0; - seg->entries = malloc(sizeof(remap_entry_ctx_t *)); - seg->entries[seg->entry_count++] = &map_entries[entry_idx]; - seg->offset = map_entries[entry_idx].virtual_offset; - map_entries[entry_idx++].segment = seg; - - while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { - map_entries[entry_idx].segment = seg; - map_entries[entry_idx - 1].next = &map_entries[entry_idx]; - remap_entry_ctx_t **ptr = calloc(1, sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1)); - memcpy(ptr, seg->entries, sizeof(remap_entry_ctx_t *) * (seg->entry_count)); - free(seg->entries); - seg->entries = ptr; - seg->entries[seg->entry_count++] = &map_entries[entry_idx++]; - } - seg->length = seg->entries[seg->entry_count - 1]->virtual_offset_end - seg->entries[0]->virtual_offset; - } - return segments; -} - -remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) { - uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits)); - if (segment_idx < ctx->header->map_segment_count) { - for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) - if (ctx->segments[segment_idx].entries[i]->virtual_offset_end > offset) - return ctx->segments[segment_idx].entries[i]; - } - return NULL; -} - -uint32_t save_remap_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - remap_entry_ctx_t *entry = save_remap_get_map_entry(ctx, offset); - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint64_t entry_pos = in_pos - entry->virtual_offset; - uint32_t bytes_to_read = entry->virtual_offset_end - in_pos < remaining ? (uint32_t)(entry->virtual_offset_end - in_pos) : remaining; - - switch (ctx->type) { - case STORAGE_BYTES: - f_lseek(ctx->file, ctx->base_storage_offset + entry->physical_offset + entry_pos); - f_read(ctx->file, (uint8_t *)buffer + out_pos, bytes_to_read, NULL); - break; - case STORAGE_DUPLEX: - save_duplex_storage_read(ctx->duplex, (uint8_t *)buffer + out_pos, ctx->base_storage_offset + entry->physical_offset + entry_pos, bytes_to_read); - break; - default: - break; - } - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - - if (in_pos >= entry->virtual_offset_end) - entry = entry->next; - } - return out_pos; -} - -uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_ctx_t *remap, void *buffer, uint64_t offset, size_t count) { - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); - uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos; - uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; - - save_remap_read(remap, (uint8_t *)buffer + out_pos, ctx->journal_data_offset + physical_offset, bytes_to_read); - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, uint64_t master_hash_offset, ivfc_save_hdr_t *ivfc) { - ivfc_level_save_ctx_t *levels = ctx->levels; - levels[0].type = STORAGE_BYTES; - levels[0].hash_offset = master_hash_offset; - for (unsigned int i = 1; i < 4; i++) { - ivfc_level_hdr_t *level = &ivfc->level_headers[i - 1]; - levels[i].type = STORAGE_REMAP; - levels[i].data_offset = level->logical_offset; - levels[i].data_size = level->hash_data_size; - } - if (ivfc->num_levels == 5) { - ivfc_level_hdr_t *data_level = &ivfc->level_headers[ivfc->num_levels - 2]; - levels[ivfc->num_levels - 1].type = STORAGE_JOURNAL; - levels[ivfc->num_levels - 1].data_offset = data_level->logical_offset; - levels[ivfc->num_levels - 1].data_size = data_level->hash_data_size; - } - - struct salt_source_t { - char string[50]; - uint32_t length; - }; - - static const struct salt_source_t salt_sources[6] = { - {"HierarchicalIntegrityVerificationStorage::Master", 48}, - {"HierarchicalIntegrityVerificationStorage::L1", 44}, - {"HierarchicalIntegrityVerificationStorage::L2", 44}, - {"HierarchicalIntegrityVerificationStorage::L3", 44}, - {"HierarchicalIntegrityVerificationStorage::L4", 44}, - {"HierarchicalIntegrityVerificationStorage::L5", 44} - }; - integrity_verification_info_ctx_t init_info[ivfc->num_levels]; - - init_info[0].data = &levels[0]; - init_info[0].block_size = 0; - for (unsigned int i = 1; i < ivfc->num_levels; i++) { - init_info[i].data = &levels[i]; - init_info[i].block_size = 1 << ivfc->level_headers[i - 1].block_size; - se_calc_hmac_sha256(init_info[i].salt, ivfc->salt_source, 0x20, salt_sources[i - 1].string, salt_sources[i - 1].length); - } - - ctx->integrity_storages[0].next_level = NULL; - ctx->level_validities = malloc(sizeof(validity_t *) * (ivfc->num_levels - 1)); - for (unsigned int i = 1; i < ivfc->num_levels; i++) { - integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1]; - level_data->hash_storage = &levels[i - 1]; - level_data->base_storage = &levels[i]; - level_data->sector_size = init_info[i].block_size; - level_data->_length = init_info[i].data->data_size; - level_data->sector_count = (level_data->_length + level_data->sector_size - 1) / level_data->sector_size; - memcpy(level_data->salt, init_info[i].salt, 0x20); - level_data->block_validities = calloc(1, sizeof(validity_t) * level_data->sector_count); - ctx->level_validities[i - 1] = level_data->block_validities; - if (i > 1) { - level_data->next_level = &ctx->integrity_storages[i - 2]; - } - } - ctx->data_level = &levels[ivfc->num_levels - 1]; - ctx->_length = ctx->integrity_storages[ivfc->num_levels - 2]._length; -} - -size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - switch (ctx->type) { - case STORAGE_BYTES: - f_lseek(ctx->save_ctx->file, ctx->hash_offset + offset); - UINT br = 0; - f_read(ctx->save_ctx->file, buffer, count, &br); - return br; - case STORAGE_REMAP: - save_remap_read(&ctx->save_ctx->meta_remap_storage, buffer, ctx->data_offset + offset, count); - return count; - case STORAGE_JOURNAL: - save_journal_storage_read(&ctx->save_ctx->journal_storage, &ctx->save_ctx->data_remap_storage, buffer, ctx->data_offset + offset, count); - return count; - default: - return 0; - } -} - -void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) { - if (count > ctx->sector_size) { - EPRINTF("IVFC read exceeds sector size!"); - return; - } - - uint64_t block_index = offset / ctx->sector_size; - - if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!", (u32)offset, count); - return; - } - - uint8_t hash_buffer[0x20] = {0}; - uint8_t zeroes[0x20] = {0}; - uint64_t hash_pos = block_index * 0x20; - if (ctx->next_level) { - save_ivfc_storage_read(ctx->next_level, hash_buffer, hash_pos, 0x20, verify); - } else { - save_ivfc_level_fread(ctx->hash_storage, hash_buffer, hash_pos, 0x20); - } - - if (!memcmp(hash_buffer, zeroes, 0x20)) { - memset(buffer, 0, count); - ctx->block_validities[block_index] = VALIDITY_VALID; - return; - } - - save_ivfc_level_fread(ctx->base_storage, buffer, offset, count); - - if (!(verify && ctx->block_validities[block_index] == VALIDITY_UNCHECKED)) { - return; - } - - uint8_t hash[0x20] = {0}; - uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20); - memcpy(data_buffer, ctx->salt, 0x20); - memcpy(data_buffer + 0x20, buffer, ctx->sector_size); - - se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20); - hash[0x1F] |= 0x80; - - free(data_buffer); - if (memcmp(hash_buffer, hash, 0x20) != 0) { - ctx->block_validities[block_index] = VALIDITY_INVALID; - } else { - ctx->block_validities[block_index] = VALIDITY_VALID; - } - - if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from current check\n found at offset %x count %x!", (u32)offset, count); - return; - } -} - -uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) { - uint32_t length = 1; - uint32_t entry_index = allocation_table_block_to_entry_index(entry->next); - uint32_t offset = entry_index * SAVE_FAT_ENTRY_SIZE; - - allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + offset); - if (allocation_table_is_single_block_segment(&entries[0])) { - if (allocation_table_is_range_entry(&entries[0])) { - EPRINTF("Invalid range entry in allocation table!"); - return 0; - } - } else { - length = entries[1].next - entry_index + 1; - } - - if (allocation_table_is_list_end(&entries[0])) { - entry->next = 0xFFFFFFFF; - } else { - entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0])); - } - - if (allocation_table_is_list_start(&entries[0])) { - entry->prev = 0xFFFFFFFF; - } else { - entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0])); - } - - return length; -} - -uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) { - allocation_table_entry_t entry; - entry.next = block_index; - uint32_t total_length = 0; - uint32_t table_size = ctx->header->allocation_table_block_count; - uint32_t nodes_iterated = 0; - - while (entry.next != 0xFFFFFFFF) { - total_length += save_allocation_table_read_entry_with_length(ctx, &entry); - nodes_iterated++; - if (nodes_iterated > table_size) { - EPRINTF("Cycle detected in allocation table!"); - return 0; - } - } - return total_length; -} - -uint64_t save_allocation_table_get_free_space_size(save_filesystem_ctx_t *ctx) { - uint32_t free_list_start = save_allocation_table_get_free_list_block_index(&ctx->allocation_table); - - if (free_list_start == 0xFFFFFFFF) return 0; - - return ctx->header->block_size * save_allocation_table_get_list_length(&ctx->allocation_table, free_list_start); -} - -void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) { - ctx->fat = table; - ctx->physical_block = initial_block; - ctx->virtual_block = 0; - - allocation_table_entry_t entry = {0, 0}; - entry.next = initial_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - if (ctx->prev_block != 0xFFFFFFFF) { - EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!", initial_block); - return; - } -} - -int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) { - if (ctx->next_block == 0xFFFFFFFF) return 0; - - ctx->virtual_block += ctx->current_segment_size; - ctx->physical_block = ctx->next_block; - - allocation_table_entry_t entry = {0, 0}; - entry.next = ctx->next_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - return 1; -} - -int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) { - if (ctx->prev_block == 0xFFFFFFFF) return 0; - - ctx->physical_block = ctx->prev_block; - - allocation_table_entry_t entry = {0, 0}; - entry.next = ctx->prev_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - ctx->virtual_block -= ctx->current_segment_size; - - return 1; -} - -int save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) { - while (1) { - if (block < ctx->virtual_block) { - if (!save_allocation_table_iterator_move_prev(ctx)) return 0; - } else if (block >= ctx->virtual_block + ctx->current_segment_size) { - if (!save_allocation_table_iterator_move_next(ctx)) return 0; - } else { - return 1; - } - - } -} - -uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - allocation_table_iterator_ctx_t iterator; - save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block); - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - save_allocation_table_iterator_seek(&iterator, block_num); - - uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size); - uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos; - - uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos; - uint32_t bytes_to_read = remaining < remaining_in_segment ? remaining : remaining_in_segment; - - uint32_t sector_size = ctx->base_storage->integrity_storages[3].sector_size; - uint32_t chunk_remaining = bytes_to_read; - for (unsigned int i = 0; i < bytes_to_read; i += sector_size) { - uint32_t bytes_to_request = chunk_remaining < sector_size ? chunk_remaining : sector_size; - save_ivfc_storage_read(&ctx->base_storage->integrity_storages[3], (uint8_t *)buffer + out_pos + i, physical_offset + i, bytes_to_request, ctx->base_storage->data_level->save_ctx->tool_ctx.action & ACTION_VERIFY); - chunk_remaining -= bytes_to_request; - } - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) { - if (!ctx->capacity) - save_allocation_table_storage_read(&ctx->storage, &ctx->capacity, 4, 4); - return ctx->capacity; -} - -uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *entry) { - return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); -} - -int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value) { - if (index >= save_fs_list_get_capacity(ctx)) { - return 0; - } - save_fs_list_read_entry(ctx, index, value); - return 1; -} - -uint32_t save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) { - save_fs_list_entry_t entry; - uint32_t capacity = save_fs_list_get_capacity(ctx); - save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry); - uint32_t prev; - if (!prev_index) { - prev_index = &prev; - } - *prev_index = ctx->used_list_head_index; - uint32_t index = entry.next; - while (index) { - if (index > capacity) { - EPRINTFARGS("Save entry index %d out of range!", index); - *prev_index = 0xFFFFFFFF; - return 0xFFFFFFFF; - } - save_fs_list_read_entry(ctx, index, &entry); - if (entry.parent == key->parent && !strcmp(entry.name, key->name)) { - return index; - } - *prev_index = index; - index = entry.next; - } - *prev_index = 0xFFFFFFFF; - return 0xFFFFFFFF; -} - -int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, const char *path) { - key->parent = 0; - const char *pos = strchr(path, '/'); - while (pos) { - memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); - const char *tmp = strchr(pos, '/'); - if (!tmp) { - memcpy(key->name, pos, strlen(pos)); - break; - } - memcpy(key->name, pos, tmp - pos); - key->parent = save_fs_list_get_index_from_key(&ctx->directory_table, key, NULL); - if (key->parent == 0xFFFFFFFF) - return 0; - pos = tmp + 1; - } - return 1; -} - -int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) { - if (position->next_file == 0) { - return 0; - } - save_fs_list_entry_t entry; - if(!save_fs_list_get_value(&ctx->file_table, position->next_file, &entry)) { - return 0; - } - position->next_file = entry.value.next_sibling; - memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); - memcpy(info, &entry.value.save_file_info, sizeof(save_file_info_t)); - return 1; -} - -int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) { - if (position->next_directory == 0) { - return 0; - } - save_fs_list_entry_t entry; - if(!save_fs_list_get_value(&ctx->directory_table, position->next_directory, &entry)) { - return 0; - } - position->next_directory = entry.value.next_sibling; - memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); - return 1; -} - -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_fs_list_entry_t *entry) { - save_entry_key_t key; - if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) { - EPRINTF("Unable to locate file."); - return 0; - } - u32 index = save_fs_list_get_index_from_key(&ctx->file_table, &key, NULL); - if (index == 0xFFFFFFFF) { - EPRINTF("Unable to get table index for file."); - return 0; - } - if (!save_fs_list_get_value(&ctx->file_table, index, entry)) { - EPRINTF("Unable to get file entry from index."); - return 0; - } - return 1; -} - -void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { - storage_ctx->base_storage = ctx->base_storage; - storage_ctx->fat = &ctx->allocation_table; - storage_ctx->block_size = (uint32_t)ctx->header->block_size; - storage_ctx->initial_block = block_index; - storage_ctx->_length = block_index == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(storage_ctx->fat, block_index) * storage_ctx->block_size; -} - -void save_filesystem_init(save_filesystem_ctx_t *ctx, void *fat, save_fs_header_t *save_fs_header, fat_header_t *fat_header) { - ctx->allocation_table.base_storage = fat; - ctx->allocation_table.header = fat_header; - ctx->allocation_table.free_list_entry_index = 0; - ctx->header = save_fs_header; - - save_open_fat_storage(ctx, &ctx->file_table.directory_table.storage, fat_header->directory_table_block); - save_open_fat_storage(ctx, &ctx->file_table.file_table.storage, fat_header->file_table_block); - ctx->file_table.file_table.free_list_head_index = 0; - ctx->file_table.file_table.used_list_head_index = 1; - ctx->file_table.directory_table.free_list_head_index = 0; - ctx->file_table.directory_table.used_list_head_index = 1; -} - -validity_t save_ivfc_validate(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { - validity_t result = VALIDITY_VALID; - for (unsigned int i = 0; i < ivfc->num_levels - 1 && result != VALIDITY_INVALID; i++) { - integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[i]; - - uint64_t block_size = storage->sector_size; - uint32_t block_count = (uint32_t)((storage->_length + block_size - 1) / block_size); - - uint8_t *buffer = malloc(block_size); - - for (unsigned int j = 0; j < block_count; j++) { - if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_UNCHECKED) { - uint32_t to_read = storage->_length - block_size * j < block_size ? storage->_length - block_size * j : block_size; - save_ivfc_storage_read(storage, buffer, block_size * j, to_read, 1); - } - if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_INVALID) { - result = VALIDITY_INVALID; - break; - } - } - free(buffer); - } - - return result; -} - -void save_ivfc_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { - for (unsigned int i = 0; i < ivfc->num_levels - 1; i++) { - validity_t level_validity = VALIDITY_VALID; - for (unsigned int j = 0; j < ctx->integrity_storages[i].sector_count; j++) { - if (ctx->level_validities[i][j] == VALIDITY_INVALID) { - level_validity = VALIDITY_INVALID; - break; - } - if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) { - level_validity = VALIDITY_UNCHECKED; - } - } - ctx->levels[i].hash_validity = level_validity; - } -} - -validity_t save_filesystem_verify(save_ctx_t *ctx) { - validity_t journal_validity = save_ivfc_validate(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); - save_ivfc_set_level_validities(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); - - if (!ctx->fat_ivfc_storage.levels[0].save_ctx) return journal_validity; - - validity_t fat_validity = save_ivfc_validate(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); - save_ivfc_set_level_validities(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); - - if (journal_validity != VALIDITY_VALID) return journal_validity; - if (fat_validity != VALIDITY_VALID) return fat_validity; - - return journal_validity; -} - -bool save_process(save_ctx_t *ctx) { - /* Try to parse Header A. */ - f_lseek(ctx->file, 0); - if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { - EPRINTF("Failed to read save header!\n"); - return false; - } - - if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { - /* Try to parse Header B. */ - f_lseek(ctx->file, 0x4000); - if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { - EPRINTF("Failed to read save header!\n"); - return false; - } - - if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { - EPRINTF("Error: Save header is invalid!"); - return false; - } - } - - unsigned char cmac[0x10] = {}; - se_aes_key_set(10, ctx->save_mac_key, 0x10); - se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); - if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { - ctx->header_cmac_validity = VALIDITY_VALID; - } else { - ctx->header_cmac_validity = VALIDITY_INVALID; - } - - /* Initialize remap storages. */ - ctx->data_remap_storage.type = STORAGE_BYTES; - ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset; - ctx->data_remap_storage.header = &ctx->header.main_remap_header; - ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); - ctx->data_remap_storage.file = ctx->file; - f_lseek(ctx->file, ctx->header.layout.file_map_entry_offset); - for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) { - f_read(ctx->file, &ctx->data_remap_storage.map_entries[i], 0x20, NULL); - ctx->data_remap_storage.map_entries[i].physical_offset_end = ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size; - ctx->data_remap_storage.map_entries[i].virtual_offset_end = ctx->data_remap_storage.map_entries[i].virtual_offset + ctx->data_remap_storage.map_entries[i].size; - } - - /* Initialize data remap storage. */ - ctx->data_remap_storage.segments = save_remap_init_segments(ctx->data_remap_storage.header, ctx->data_remap_storage.map_entries, ctx->data_remap_storage.header->map_entry_count); - - /* Initialize duplex storage. */ - ctx->duplex_layers[0].data_a = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_a; - ctx->duplex_layers[0].data_b = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_b; - memcpy(&ctx->duplex_layers[0].info, &ctx->header.duplex_header.layers[0], sizeof(duplex_info_t)); - - ctx->duplex_layers[1].data_a = malloc(ctx->header.layout.duplex_l1_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size); - ctx->duplex_layers[1].data_b = malloc(ctx->header.layout.duplex_l1_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size); - memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t)); - - ctx->duplex_layers[2].data_a = malloc(ctx->header.layout.duplex_data_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size); - ctx->duplex_layers[2].data_b = malloc(ctx->header.layout.duplex_data_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size); - memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t)); - - /* Initialize hierarchical duplex storage. */ - uint8_t *bitmap = ctx->header.layout.duplex_index == 1 ? ctx->duplex_layers[0].data_b : ctx->duplex_layers[0].data_a; - save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size); - ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size; - - bitmap = malloc(ctx->duplex_storage.layers[0]._length); - save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length); - save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length); - ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size; - - ctx->duplex_storage.data_layer = ctx->duplex_storage.layers[1]; - - /* Initialize meta remap storage. */ - ctx->meta_remap_storage.type = STORAGE_DUPLEX; - ctx->meta_remap_storage.duplex = &ctx->duplex_storage.data_layer; - ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; - ctx->meta_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); - ctx->meta_remap_storage.file = ctx->file; - f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset); - for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) { - f_read(ctx->file, &ctx->meta_remap_storage.map_entries[i], 0x20, NULL); - ctx->meta_remap_storage.map_entries[i].physical_offset_end = ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size; - ctx->meta_remap_storage.map_entries[i].virtual_offset_end = ctx->meta_remap_storage.map_entries[i].virtual_offset + ctx->meta_remap_storage.map_entries[i].size; - } - - ctx->meta_remap_storage.segments = save_remap_init_segments(ctx->meta_remap_storage.header, ctx->meta_remap_storage.map_entries, ctx->meta_remap_storage.header->map_entry_count); - - /* Initialize journal map. */ - ctx->journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size); - save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size); - - /* Initialize journal storage. */ - ctx->journal_storage.header = &ctx->header.journal_header; - ctx->journal_storage.journal_data_offset = ctx->header.layout.journal_data_offset; - ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; - ctx->journal_storage.file = ctx->file; - ctx->journal_storage.map.header = &ctx->header.map_header; - ctx->journal_storage.map.map_storage = ctx->journal_map_info.map_storage; - ctx->journal_storage.map.entries = malloc(sizeof(journal_map_entry_t) * ctx->journal_storage.map.header->main_data_block_count); - uint32_t *pos = (uint32_t *)ctx->journal_storage.map.map_storage; - for (unsigned int i = 0; i < ctx->journal_storage.map.header->main_data_block_count; i++) { - ctx->journal_storage.map.entries[i].virtual_index = i; - ctx->journal_storage.map.entries[i].physical_index = *pos & 0x7FFFFFFF; - pos += 2; - } - ctx->journal_storage.block_size = ctx->journal_storage.header->block_size; - ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; - - /* Initialize core IVFC storage. */ - for (unsigned int i = 0; i < 5; i++) { - ctx->core_data_ivfc_storage.levels[i].save_ctx = ctx; - } - save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header); - - /* Initialize FAT storage. */ - if (ctx->header.layout.version < 0x50000) { - ctx->fat_storage = malloc(ctx->header.layout.fat_size); - save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size); - } else { - for (unsigned int i = 0; i < 5; i++) { - ctx->fat_ivfc_storage.levels[i].save_ctx = ctx; - } - save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header); - ctx->fat_storage = malloc(ctx->fat_ivfc_storage._length); - save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length); - } - - if (ctx->tool_ctx.action & ACTION_VERIFY) { - save_filesystem_verify(ctx); - } - - /* Initialize core save filesystem. */ - ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage; - save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header); - - return true; -} - -bool save_process_header(save_ctx_t *ctx) { - if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS || - ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL || - ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || - ctx->header.meta_remap_header.magic != MAGIC_RMAP) - { - EPRINTF("Error: Save header is corrupt!"); - return false; - } - - ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; - ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; - - uint8_t hash[0x20]; - se_calc_sha256(hash, &ctx->header.duplex_header, 0x3D00); - ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; - - ctx->header.data_ivfc_header.num_levels = 5; - - if (ctx->header.layout.version >= 0x50000) { - ctx->header.fat_ivfc_header.num_levels = 4; - } - return true; -} - -void save_free_contexts(save_ctx_t *ctx) { - for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { - free(ctx->data_remap_storage.segments[i].entries); - } - free(ctx->data_remap_storage.segments); - for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { - free(ctx->meta_remap_storage.segments[i].entries); - } - free(ctx->meta_remap_storage.segments); - free(ctx->data_remap_storage.map_entries); - free(ctx->meta_remap_storage.map_entries); - free(ctx->duplex_storage.layers[0].bitmap.bitmap); - free(ctx->duplex_storage.layers[1].bitmap.bitmap); - free(ctx->duplex_storage.layers[1].bitmap_storage); - for (unsigned int i = 1; i < 3; i++) { - free(ctx->duplex_layers[i].data_a); - free(ctx->duplex_layers[i].data_b); - } - free(ctx->journal_map_info.map_storage); - free(ctx->journal_storage.map.entries); - for (unsigned int i = 0; i < ctx->header.data_ivfc_header.num_levels - 1; i++) { - free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); - } - free(ctx->core_data_ivfc_storage.level_validities); - if (ctx->header.layout.version >= 0x50000) { - for (unsigned int i = 0; i < ctx->header.fat_ivfc_header.num_levels - 1; i++) { - free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); - } - } - free(ctx->fat_ivfc_storage.level_validities); - free(ctx->fat_storage); -} diff --git a/source/keys/save.h b/source/keys/save.h deleted file mode 100644 index 2e11f4a..0000000 --- a/source/keys/save.h +++ /dev/null @@ -1,526 +0,0 @@ -#ifndef _SAVE_H -#define _SAVE_H - -#include -#include - -#include - -#define SAVE_HEADER_SIZE 0x4000 -#define SAVE_FAT_ENTRY_SIZE 8 -#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40 -#define SAVE_FS_LIST_ENTRY_SIZE 0x60 - -#define IVFC_MAX_LEVEL 6 - -#define MAGIC_DISF 0x46534944 -#define MAGIC_DPFS 0x53465044 -#define MAGIC_JNGL 0x4C474E4A -#define MAGIC_SAVE 0x45564153 -#define MAGIC_RMAP 0x50414D52 -#define MAGIC_IVFC 0x43465649 - -typedef enum { - VALIDITY_UNCHECKED = 0, - VALIDITY_INVALID, - VALIDITY_VALID -} validity_t; - -typedef struct save_ctx_t save_ctx_t; - -typedef struct { - uint32_t magic; /* DISF */ - uint32_t version; - uint8_t hash[0x20]; - uint64_t file_map_entry_offset; - uint64_t file_map_entry_size; - uint64_t meta_map_entry_offset; - uint64_t meta_map_entry_size; - uint64_t file_map_data_offset; - uint64_t file_map_data_size; - uint64_t duplex_l1_offset_a; - uint64_t duplex_l1_offset_b; - uint64_t duplex_l1_size; - uint64_t duplex_data_offset_a; - uint64_t duplex_data_offset_b; - uint64_t duplex_data_size; - uint64_t journal_data_offset; - uint64_t journal_data_size_a; - uint64_t journal_data_size_b; - uint64_t journal_size; - uint64_t duplex_master_offset_a; - uint64_t duplex_master_offset_b; - uint64_t duplex_master_size; - uint64_t ivfc_master_hash_offset_a; - uint64_t ivfc_master_hash_offset_b; - uint64_t ivfc_master_hash_size; - uint64_t journal_map_table_offset; - uint64_t journal_map_table_size; - uint64_t journal_physical_bitmap_offset; - uint64_t journal_physical_bitmap_size; - uint64_t journal_virtual_bitmap_offset; - uint64_t journal_virtual_bitmap_size; - uint64_t journal_free_bitmap_offset; - uint64_t journal_free_bitmap_size; - uint64_t ivfc_l1_offset; - uint64_t ivfc_l1_size; - uint64_t ivfc_l2_offset; - uint64_t ivfc_l2_size; - uint64_t ivfc_l3_offset; - uint64_t ivfc_l3_size; - uint64_t fat_offset; - uint64_t fat_size; - uint64_t duplex_index; - uint64_t fat_ivfc_master_hash_a; - uint64_t fat_ivfc_master_hash_b; - uint64_t fat_ivfc_l1_offset; - uint64_t fat_ivfc_l1_size; - uint64_t fat_ivfc_l2_offset; - uint64_t fat_ivfc_l2_size; - uint8_t _0x190[0x70]; -} fs_layout_t; - -#pragma pack(push, 1) -typedef struct { - uint64_t offset; - uint64_t length; - uint32_t block_size_power; -} duplex_info_t; -#pragma pack(pop) - -typedef struct { - uint32_t magic; /* DPFS */ - uint32_t version; - duplex_info_t layers[3]; -} duplex_header_t; - -typedef struct { - uint32_t version; - uint32_t main_data_block_count; - uint32_t journal_block_count; - uint32_t _0x0C; -} journal_map_header_t; - -typedef struct { - uint32_t magic; /* JNGL */ - uint32_t version; - uint64_t total_size; - uint64_t journal_size; - uint64_t block_size; -} journal_header_t; - -typedef struct { - uint32_t magic; /* SAVE */ - uint32_t version; - uint64_t block_count; - uint64_t block_size; -} save_fs_header_t; - -typedef struct { - uint64_t block_size; - uint64_t allocation_table_offset; - uint32_t allocation_table_block_count; - uint32_t _0x14; - uint64_t data_offset; - uint32_t data_block_count; - uint32_t _0x24; - uint32_t directory_table_block; - uint32_t file_table_block; -} fat_header_t; - -typedef struct { - uint32_t magic; /* RMAP */ - uint32_t version; - uint32_t map_entry_count; - uint32_t map_segment_count; - uint32_t segment_bits; - uint8_t _0x14[0x2C]; -} remap_header_t; - -typedef struct remap_segment_ctx_t remap_segment_ctx_t; -typedef struct remap_entry_ctx_t remap_entry_ctx_t; - -#pragma pack(push, 1) -struct remap_entry_ctx_t { - uint64_t virtual_offset; - uint64_t physical_offset; - uint64_t size; - uint32_t alignment; - uint32_t _0x1C; - uint64_t virtual_offset_end; - uint64_t physical_offset_end; - remap_segment_ctx_t *segment; - remap_entry_ctx_t *next; -}; -#pragma pack(pop) - -struct remap_segment_ctx_t{ - uint64_t offset; - uint64_t length; - remap_entry_ctx_t **entries; - uint64_t entry_count; -}; - -typedef struct { - uint8_t *data; - uint8_t *bitmap; -} duplex_bitmap_t; - -typedef struct { - uint32_t block_size; - uint8_t *bitmap_storage; - uint8_t *data_a; - uint8_t *data_b; - duplex_bitmap_t bitmap; - uint64_t _length; -} duplex_storage_ctx_t; - -enum base_storage_type { - STORAGE_BYTES = 0, - STORAGE_DUPLEX = 1, - STORAGE_REMAP = 2, - STORAGE_JOURNAL = 3 -}; - -typedef struct { - remap_header_t *header; - remap_entry_ctx_t *map_entries; - remap_segment_ctx_t *segments; - enum base_storage_type type; - uint64_t base_storage_offset; - duplex_storage_ctx_t *duplex; - FIL *file; -} remap_storage_ctx_t; - -typedef struct { - uint64_t program_id; - uint8_t user_id[0x10]; - uint64_t save_id; - uint8_t save_data_type; - uint8_t _0x21[0x1F]; - uint64_t save_owner_id; - uint64_t timestamp; - uint64_t _0x50; - uint64_t data_size; - uint64_t journal_size; - uint64_t commit_id; -} extra_data_t; - -typedef struct { - uint64_t logical_offset; - uint64_t hash_data_size; - uint32_t block_size; - uint32_t reserved; -} ivfc_level_hdr_t; - -typedef struct { - uint32_t magic; - uint32_t id; - uint32_t master_hash_size; - uint32_t num_levels; - ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL]; - uint8_t salt_source[0x20]; -} ivfc_save_hdr_t; - -#pragma pack(push, 1) -typedef struct { - uint8_t cmac[0x10]; - uint8_t _0x10[0xF0]; - fs_layout_t layout; - duplex_header_t duplex_header; - ivfc_save_hdr_t data_ivfc_header; - uint32_t _0x404; - journal_header_t journal_header; - journal_map_header_t map_header; - uint8_t _0x438[0x1D0]; - save_fs_header_t save_header; - fat_header_t fat_header; - remap_header_t main_remap_header, meta_remap_header; - uint64_t _0x6D0; - extra_data_t extra_data; - uint8_t _0x748[0x390]; - ivfc_save_hdr_t fat_ivfc_header; - uint8_t _0xB98[0x3468]; -} save_header_t; -#pragma pack(pop) - -typedef struct { - duplex_storage_ctx_t layers[2]; - duplex_storage_ctx_t data_layer; - uint64_t _length; -} hierarchical_duplex_storage_ctx_t; - -typedef struct { - uint8_t *data_a; - uint8_t *data_b; - duplex_info_t info; -} duplex_fs_layer_info_t; - -typedef struct { - uint8_t *map_storage; - uint8_t *physical_block_bitmap; - uint8_t *virtual_block_bitmap; - uint8_t *free_block_bitmap; -} journal_map_params_t; - -typedef struct { - uint32_t physical_index; - uint32_t virtual_index; -} journal_map_entry_t; - - -typedef struct { - journal_map_header_t *header; - journal_map_entry_t *entries; - uint8_t *map_storage; -} journal_map_ctx_t; - -typedef struct { - journal_map_ctx_t map; - journal_header_t *header; - uint32_t block_size; - uint64_t journal_data_offset; - uint64_t _length; - FIL *file; -} journal_storage_ctx_t; - -typedef struct { - uint64_t data_offset; - uint64_t data_size; - uint64_t hash_offset; - uint32_t hash_block_size; - validity_t hash_validity; - enum base_storage_type type; - save_ctx_t *save_ctx; -} ivfc_level_save_ctx_t; - -typedef struct { - ivfc_level_save_ctx_t *data; - uint32_t block_size; - uint8_t salt[0x20]; -} integrity_verification_info_ctx_t; - - -typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t; - -struct integrity_verification_storage_ctx_t { - ivfc_level_save_ctx_t *hash_storage; - ivfc_level_save_ctx_t *base_storage; - validity_t *block_validities; - uint8_t salt[0x20]; - uint32_t sector_size; - uint32_t sector_count; - uint64_t _length; - integrity_verification_storage_ctx_t *next_level; -}; - -typedef struct { - ivfc_level_save_ctx_t levels[5]; - ivfc_level_save_ctx_t *data_level; - validity_t **level_validities; - uint64_t _length; - integrity_verification_storage_ctx_t integrity_storages[4]; -} hierarchical_integrity_verification_storage_ctx_t; - -typedef struct { - uint32_t prev; - uint32_t next; -} allocation_table_entry_t; - -typedef struct { - uint32_t free_list_entry_index; - void *base_storage; - fat_header_t *header; -} allocation_table_ctx_t; - -typedef struct { - hierarchical_integrity_verification_storage_ctx_t *base_storage; - uint32_t block_size; - uint32_t initial_block; - allocation_table_ctx_t *fat; - uint64_t _length; -} allocation_table_storage_ctx_t; - -typedef struct { - allocation_table_ctx_t *fat; - uint32_t virtual_block; - uint32_t physical_block; - uint32_t current_segment_size; - uint32_t next_block; - uint32_t prev_block; -} allocation_table_iterator_ctx_t; - -typedef struct { - char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; - uint32_t parent; -} save_entry_key_t; - -#pragma pack(push, 1) -typedef struct { - uint32_t start_block; - uint64_t length; - uint32_t _0xC[2]; -} save_file_info_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t next_directory; - uint32_t next_file; - uint32_t _0x8[3]; -} save_find_position_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t next_sibling; - union { /* Save table entry type. Size = 0x14. */ - save_file_info_t save_file_info; - save_find_position_t save_find_position; - }; -} save_table_entry_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t parent; - char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; - save_table_entry_t value; - uint32_t next; -} save_fs_list_entry_t; -#pragma pack(pop) - -typedef struct { - uint32_t free_list_head_index; - uint32_t used_list_head_index; - allocation_table_storage_ctx_t storage; - uint32_t capacity; -} save_filesystem_list_ctx_t; - -typedef struct { - save_filesystem_list_ctx_t file_table; - save_filesystem_list_ctx_t directory_table; -} hierarchical_save_file_table_ctx_t; - -typedef struct { - hierarchical_integrity_verification_storage_ctx_t *base_storage; - allocation_table_ctx_t allocation_table; - save_fs_header_t *header; - hierarchical_save_file_table_ctx_t file_table; -} save_filesystem_ctx_t; - -#define ACTION_VERIFY (1<<2) - -struct save_ctx_t { - save_header_t header; - FIL *file; - struct { - FIL *file; - uint32_t action; - } tool_ctx; - validity_t header_cmac_validity; - validity_t header_hash_validity; - uint8_t *data_ivfc_master; - uint8_t *fat_ivfc_master; - remap_storage_ctx_t data_remap_storage; - remap_storage_ctx_t meta_remap_storage; - duplex_fs_layer_info_t duplex_layers[3]; - hierarchical_duplex_storage_ctx_t duplex_storage; - journal_storage_ctx_t journal_storage; - journal_map_params_t journal_map_info; - hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage; - hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage; - uint8_t *fat_storage; - save_filesystem_ctx_t save_filesystem_core; - uint8_t save_mac_key[0x10]; -}; - -static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) { - return entry_index - 1; -} - -static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) { - return block_index + 1; -} - -static inline int allocation_table_get_prev(allocation_table_entry_t *entry) { - return entry->prev & 0x7FFFFFFF; -} - -static inline int allocation_table_get_next(allocation_table_entry_t *entry) { - return entry->next & 0x7FFFFFFF; -} - -static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) { - return entry->prev == 0x80000000; -} - -static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) { - return (entry->next & 0x7FFFFFFF) == 0; -} - -static inline bool allocation_table_is_multi_block_segment(allocation_table_entry_t *entry) { - return entry->next & 0x80000000; -} - -static inline void allocation_table_make_multi_block_segment(allocation_table_entry_t *entry) { - entry->next |= 0x80000000; -} - -static inline void allocation_table_make_single_block_segment(allocation_table_entry_t *entry) { - entry->next &= 0x7FFFFFFF; -} - -static inline bool allocation_table_is_single_block_segment(allocation_table_entry_t *entry) { - return (entry->next & 0x80000000) == 0; -} - -static inline void allocation_table_make_list_start(allocation_table_entry_t *entry) { - entry->prev = 0x80000000; -} - -static inline bool allocation_table_is_range_entry(allocation_table_entry_t *entry) { - return (entry->prev & 0x80000000) != 0 && entry->prev != 0x80000000; -} - -static inline void allocation_table_make_range_entry(allocation_table_entry_t *entry) { - entry->prev |= 0x80000000; -} - -static inline void allocation_table_set_next(allocation_table_entry_t *entry, int val) { - entry->next = (entry->next & 0x80000000) | val; -} - -static inline void allocation_table_set_prev(allocation_table_entry_t *entry, int val) { - entry->prev = val; -} - -static inline void allocation_table_set_range(allocation_table_entry_t *entry, int start_index, int end_index) { - entry->next = end_index; - entry->prev = start_index; - allocation_table_make_range_entry(entry); -} - -static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { - return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE); -} - -static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) { - return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index)); -} - -static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) { - return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); -} - -bool save_process(save_ctx_t *ctx); -bool save_process_header(save_ctx_t *ctx); - -void save_free_contexts(save_ctx_t *ctx); - -void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index); -uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count); -int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value); -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, const char *path, save_fs_list_entry_t *entry); - -#endif From 5d101cad50ef9c96b61afda6582538d7820178e5 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 4 Dec 2020 11:20:01 -0700 Subject: [PATCH 086/166] Update to Hekate bdk 5.5.0, prelim Mariko support --- Makefile | 7 +- bdk/gfx/di.c | 450 +++- bdk/gfx/di.h | 348 ++- bdk/gfx/di.inl | 156 +- bdk/input/als.c | 3 +- bdk/input/als.h | 4 +- bdk/input/joycon.c | 43 +- bdk/input/touch.c | 2 +- bdk/libs/compr/lz.c | 6 +- bdk/libs/compr/lz.h | 2 +- bdk/libs/compr/lz4.c | 1672 ++++++++++++++ bdk/libs/compr/lz4.h | 569 +++++ bdk/libs/fatfs/diskio.h | 2 + bdk/libs/fatfs/ff.c | 144 +- bdk/libs/fatfs/ff.h | 6 +- bdk/libs/lv_conf.h | 6 +- bdk/libs/lvgl/lv_misc/lv_log.c | 2 +- bdk/mem/emc.h | 41 +- bdk/mem/mc.c | 13 +- bdk/mem/mc_t210.h | 13 +- bdk/mem/minerva.c | 7 +- bdk/mem/sdram.c | 830 ++++++- bdk/mem/sdram.h | 72 +- bdk/mem/sdram_config.inl | 35 +- bdk/mem/sdram_config_t210b01.inl | 1002 ++++++++ bdk/mem/sdram_lp0.c | 434 +++- bdk/mem/sdram_lp0_param_t210.h | 6 +- bdk/mem/sdram_lp0_param_t210b01.h | 990 ++++++++ bdk/mem/sdram_param_t210.h | 4 +- bdk/mem/sdram_param_t210b01.h | 989 ++++++++ bdk/memory_map.h | 13 +- bdk/power/bm92t36.c | 99 + bdk/power/bm92t36.h | 41 + bdk/power/max17050.c | 38 +- bdk/power/max17050.h | 8 +- bdk/power/max77620.h | 130 +- bdk/power/max7762x.c | 28 +- bdk/power/max7762x.h | 22 +- bdk/power/max77812.h | 100 + bdk/power/regulator_5v.h | 6 +- bdk/rtc/max77620-rtc.h | 12 +- bdk/sec/se_t210.h | 115 +- bdk/sec/tsec_t210.h | 28 +- bdk/soc/bpmp.c | 72 +- bdk/soc/ccplex.c | 66 +- bdk/soc/clock.c | 217 +- bdk/soc/clock.h | 301 ++- bdk/soc/fuse.c | 56 +- bdk/soc/fuse.h | 18 +- bdk/soc/gpio.c | 30 +- bdk/soc/gpio.h | 16 +- bdk/soc/hw_init.c | 276 ++- bdk/soc/hw_init.h | 5 +- bdk/soc/i2c.c | 342 ++- bdk/soc/i2c.h | 25 +- bdk/soc/irq.c | 8 +- bdk/soc/irq.h | 4 +- bdk/soc/kfuse.h | 16 +- bdk/soc/pinmux.h | 31 +- bdk/soc/pmc.c | 52 + bdk/soc/pmc.h | 38 +- bdk/soc/t210.h | 100 +- bdk/storage/mmc.h | 8 +- bdk/storage/sdmmc.c | 140 +- bdk/storage/sdmmc.h | 11 +- bdk/storage/sdmmc_driver.c | 438 ++-- bdk/storage/sdmmc_driver.h | 16 +- bdk/storage/sdmmc_t210.h | 1 + bdk/thermal/fan.c | 4 +- bdk/usb/usb_descriptor_types.h | 238 ++ .../{usb_descriptors.h => usb_descriptors.c} | 412 +--- bdk/usb/usb_gadget_hid.c | 37 +- bdk/usb/usb_gadget_ums.c | 156 +- bdk/usb/usb_t210.h | 200 +- bdk/usb/usbd.c | 758 +++--- bdk/usb/usbd.h | 191 +- bdk/usb/xusbd.c | 2022 +++++++++++++++++ bdk/utils/btn.h | 8 +- bdk/utils/types.h | 22 +- bdk/utils/util.c | 23 +- bdk/utils/util.h | 21 +- source/config.c | 7 +- source/config.h | 7 +- source/hos/fss.c | 48 +- source/hos/hos.h | 18 +- source/hos/pkg1.c | 2 +- source/hos/sept.c | 2 +- source/main.c | 24 +- source/storage/emummc.c | 4 +- 89 files changed, 12779 insertions(+), 2210 deletions(-) create mode 100644 bdk/libs/compr/lz4.c create mode 100644 bdk/libs/compr/lz4.h create mode 100644 bdk/mem/sdram_config_t210b01.inl create mode 100644 bdk/mem/sdram_lp0_param_t210b01.h create mode 100644 bdk/mem/sdram_param_t210b01.h create mode 100644 bdk/power/bm92t36.c create mode 100644 bdk/power/bm92t36.h create mode 100644 bdk/power/max77812.h create mode 100644 bdk/soc/pmc.c create mode 100644 bdk/usb/usb_descriptor_types.h rename bdk/usb/{usb_descriptors.h => usb_descriptors.c} (65%) create mode 100644 bdk/usb/xusbd.c diff --git a/Makefile b/Makefile index d303560..c10c9d3 100644 --- a/Makefile +++ b/Makefile @@ -40,8 +40,13 @@ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) +# 0: UART_A, 1: UART_B. +#CUSTOMDEFINES += -DDEBUG_UART_PORT=0 + +#CUSTOMDEFINES += -DDEBUG + ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fno-inline -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) ################################################################################ diff --git a/bdk/gfx/di.c b/bdk/gfx/di.c index 1549e7b..9d95349 100644 --- a/bdk/gfx/di.c +++ b/bdk/gfx/di.c @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ extern volatile nyx_storage_t *nyx_str; static u32 _display_id = 0; -void display_end(); +static void _display_panel_and_hw_end(bool no_panel_deinit); static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) { @@ -53,91 +54,309 @@ static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait) usleep(wait); } +static void _display_dsi_read_rx_fifo(u32 *data) +{ + u32 fifo_count = DSI(_DSIREG(DSI_STATUS)) & DSI_STATUS_RX_FIFO_SIZE; + for (u32 i = 0; i < fifo_count; i++) + { + // Read or Drain RX FIFO. + if (data) + data[i] = DSI(_DSIREG(DSI_RD_DATA)); + else + (void)DSI(_DSIREG(DSI_RD_DATA)); + } +} + +int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled) +{ + int res = 0; + u32 host_control = 0; + u32 cmd_timeout = video_enabled ? 0 : 250000; + u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0}; + + // Drain RX FIFO. + _display_dsi_read_rx_fifo(NULL); + + // Save host control and enable host cmd packets during video. + if (video_enabled) + { + host_control = DSI(_DSIREG(DSI_HOST_CONTROL)); + + // Enable vblank interrupt. + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = DC_CMD_INT_FRAME_END_INT; + + // Use the 4th line to transmit the host cmd packet. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4); + + // Wait for vblank before starting the transfer. + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. + while (DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT) + ; + } + + // Set reply size. + _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); + _display_dsi_wait(cmd_timeout, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + // Request register read. + _display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0); + _display_dsi_wait(cmd_timeout, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + // Transfer bus control to device for transmitting the reply. + u32 high_speed = video_enabled ? DSI_HOST_CONTROL_HS : 0; + DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC | high_speed; + _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); + + // Wait a bit for the reply. + usleep(5000); + + // Read RX FIFO. + _display_dsi_read_rx_fifo(fifo); + + // Parse packet and copy over the data. + if ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD) + { + // Act based on reply type. + switch (fifo[1] & 0xFF) + { + case GEN_LONG_RD_RES: + case DCS_LONG_RD_RES: + memcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len)); + break; + + case GEN_1_BYTE_SHORT_RD_RES: + case DCS_1_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 1); + break; + + case GEN_2_BYTE_SHORT_RD_RES: + case DCS_2_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 2); + break; + case ACK_ERROR_RES: + default: + res = 1; + break; + } + } + + // Disable host cmd packets during video and restore host control. + if (video_enabled) + { + // Wait for vblank before reseting sync points. + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. + while (DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT) + ; + + // Reset all states of syncpt block. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = DSI_INCR_SYNCPT_SOFT_RESET; + usleep(300); // Stabilization delay. + + // Clear syncpt block reset. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = 0; + usleep(300); // Stabilization delay. + + // Restore video mode and host control. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; + + // Disable and clear vblank interrupt. + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = 0; + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; + } + + return res; +} + +void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) +{ + u32 host_control; + u32 fifo32[DSI_STATUS_RX_FIFO_SIZE] = {0}; + u8 *fifo8 = (u8 *)fifo32; + + // Enable host cmd packets during video and save host control. + if (video_enabled) + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE; + host_control = DSI(_DSIREG(DSI_HOST_CONTROL)); + + // Enable host transfer trigger. + DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_TX_TRIG_HOST; + + switch (len) + { + case 0: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, cmd, 0); + break; + + case 1: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd | (*(u8 *)data << 8), 0); + break; + + default: + fifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE; + fifo8[4] = cmd; + memcpy(&fifo8[5], data, len); + len += 4 + 1; // Increase length by CMD/length word and DCS CMD. + for (u32 i = 0; i < (ALIGN(len, 4) / 4); i++) + DSI(_DSIREG(DSI_WR_DATA)) = fifo32[i]; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + break; + } + + // Wait for the write to happen. + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST); + + // Disable host cmd packets during video and restore host control. + if (video_enabled) + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; +} + void display_init() { // Check if display is already initialized. - if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & 0x18000000) - display_end(); + if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & BIT(CLK_L_DISP1)) + _display_panel_and_hw_end(true); - // Power on. + // Get Chip ID. + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + // T210B01: Power on SD2 regulator for supplying LD0. + if (!tegra_t210) + { + // Set SD2 regulator voltage. + max77620_regulator_set_voltage(REGULATOR_SD2, 1325000); + + // Set slew rate and enable SD2 regulator. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT) | MAX77620_SD_CFG1_FSRADE_SD_ENABLE); + max77620_regulator_enable(REGULATOR_SD2, 1); + + } + + // Enable power to display panel controller. max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); + if (tegra_t210) + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, + MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); // T210: LD0 -> GPIO7 -> Display panel. // Enable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_UART_FST_MIPI_CAL); CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_DSIA_LP); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). - // Disable deep power down. - PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; - PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; + // Bring every IO rail out of deep power down. + PMC(APBDEV_PMC_IO_DPD_REQ) = PMC_IO_DPD_REQ_DPD_OFF; + PMC(APBDEV_PMC_IO_DPD2_REQ) = PMC_IO_DPD_REQ_DPD_OFF; - // Config LCD and Backlight pins. - PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN - PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; // PULL_DOWN + // Configure LCD pins. + PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; // PULL_DOWN + + // Configure Backlight pins. PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; // PULL_DOWN | 1 - PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN - PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN - // Set Backlight +-5V pins mode and direction + // Set LCD +-5V pins mode and direction gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); - // Enable Backlight power. - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. + // Enable LCD power. + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // LCD +5V enable. usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // LCD -5V enable. usleep(10000); - // Configure Backlight pins (PWM, EN, RST). + // Configure Backlight PWM/EN and LCD RST pins (BL PWM, BL EN, LCD RST). gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. + + // Enable Backlight power. + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Power up supply regulator for display interface. MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0; + if (!tegra_t210) + { + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG0)) = 0; + APB_MISC(APB_MISC_GP_DSI_PAD_CONTROL) = 0; + } + // Set DISP1 clock source and parent clock. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT. u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 96 MHz. CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; - CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP. - CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2D0AAA; // PLLD_ENABLE_CLK. + + if (tegra_t210) + { + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP. + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2D0AAA; // PLLD_ENABLE_CLK. + } + else + { + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // PLLD_ENABLE_CLK. + } + + // Setup Display Interface initial window configuration. + exec_cfg((u32 *)DISPLAY_A_BASE, _display_dc_setup_win_config, 94); // Setup display communication interfaces. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_dc_setup_win_config, 94); - exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config, 61); + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part1, 8); + if (tegra_t210) + DSI(_DSIREG(DSI_INIT_SEQ_DATA_15)) = 0; + else + DSI(_DSIREG(DSI_INIT_SEQ_DATA_15_B01)) = 0; + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part2, 14); + if (!tegra_t210) + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part3_t210b01, 7); + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part4, 10); + DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part5, 12); + DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config_part6, 14); usleep(10000); - // Enable Backlight Reset. + // Enable LCD Reset. gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); usleep(60000); - // Setups DSI packet configuration and request display id. + // Setup DSI device takeover timeout. DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; + +#if 0 + // Get Display ID. + _display_id = 0xCCCCCC; + display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id, DSI_VIDEO_DISABLED); +#else + // Set reply size. _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + // Request register read. _display_dsi_send_cmd(MIPI_DSI_DCS_READ, MIPI_DCS_GET_DISPLAY_ID, 0); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + // Transfer bus control to device for transmitting the reply. DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); + // Wait a bit for the reply. usleep(5000); - // MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 u32. + // MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 x u32. for (u32 i = 0; i < 3; i++) - _display_id = DSI(_DSIREG(DSI_RD_DATA)); // Skip ack and msg type info and get the payload (display id). - + _display_id = DSI(_DSIREG(DSI_RD_DATA)) & 0xFFFFFF; // Skip ack and msg type info and get the payload (display id). +#endif // Save raw Display ID to Nyx storage. nyx_str->info.disp_id = _display_id; @@ -154,47 +373,82 @@ void display_init() exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); break; + case PANEL_INL_P062CCA_AZ1: case PANEL_AUO_A062TAN01: _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + + // Unlock extension cmds. DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; usleep(5000); + + // Set Power control. DSI(_DSIREG(DSI_WR_DATA)) = 0x739; // MIPI_DSI_DCS_LONG_WRITE: 7 bytes. if (_display_id == PANEL_INL_P062CCA_AZ1) - DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). - else - DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else // PANEL_AUO_A062TAN01. + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). DSI(_DSIREG(DSI_WR_DATA)) = 0x143209; // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32). DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; usleep(5000); break; - case PANEL_INL_P062CCA_AZ2: - case PANEL_AUO_A062TAN02: + + case PANEL_INL_2J055IA_27A: + case PANEL_AUO_A055TAN01: + case PANEL_V40_55_UNK: default: // Allow spare part displays to work. _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000); break; } + // Unblank display. _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); // Configure PLLD for DISP1. - plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 460.8 MHz. + plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 230.4 MHz. CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; - CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; - CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN. + + if (tegra_t210) + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP + else + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN. // Finalize DSI configuration. - exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 21); - DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; // PCD1 | div3. + DSI(_DSIREG(DSI_PAD_CONTROL_1)) = 0; + DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; + exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 19); + // Set pixel clock dividers: 230.4 / 3 / 1 = 76.8 MHz. 60 Hz. + DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // 4: div3. exec_cfg((u32 *)DSI_BASE, _display_dsi_mode_config, 10); usleep(10000); // Calibrate display communication pads. - exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_pad_cal_config, 6); - exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config, 4); - exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_apply_dsi_cal_config, 16); + u32 loops = tegra_t210 ? 1 : 2; // Find out why this is done 2 times on Mariko. + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_pad_cal_config, 4); + for (u32 i = 0; i < loops; i++) + { + // Set MIPI bias pad config. + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0x10010; + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG1)) = tegra_t210 ? 0x300 : 0; + + // Set pad trimmers and set MIPI DSI cal offsets. + if (tegra_t210) + { + exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config_t210, 4); + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_dsi_cal_offsets_config_t210, 4); + } + else + { + exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config_t210b01, 7); + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_dsi_cal_offsets_config_t210b01, 4); + } + + // Set the rest of MIPI cal offsets and apply calibration. + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_apply_dsi_cal_config, 12); + } usleep(10000); // Enable video display controller. @@ -205,9 +459,9 @@ void display_backlight_pwm_init() { clock_enable_pwm(); - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. 29.5KHz is stock. - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. } @@ -245,15 +499,22 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; } -void display_end() +static void _display_panel_and_hw_end(bool no_panel_deinit) { + if (no_panel_deinit) + goto skip_panel_deinit; + display_backlight_brightness(0, 1000); + // Enable host cmd packets during video. DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE; - DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF + // Blank display. + DSI(_DSIREG(DSI_WR_DATA)) = (MIPI_DCS_SET_DISPLAY_OFF << 8) | MIPI_DSI_DCS_SHORT_WRITE; + + // Propagate changes to all register buffers and disable host cmd packets during video. DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // De-initialize video controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17); @@ -266,59 +527,82 @@ void display_end() case PANEL_JDI_XXX062M: exec_cfg((u32 *)DSI_BASE, _display_deinit_config_jdi, 22); break; + case PANEL_AUO_A062TAN01: exec_cfg((u32 *)DSI_BASE, _display_deinit_config_auo, 37); break; - case PANEL_INL_P062CCA_AZ2: - case PANEL_AUO_A062TAN02: - DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + + case PANEL_INL_2J055IA_27A: + case PANEL_AUO_A055TAN01: + case PANEL_V40_55_UNK: + // Unlock extension cmds. + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; usleep(5000); - // Set Power. - DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. - if (_display_id == PANEL_INL_P062CCA_AZ2) - DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). - else - DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). - // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). - DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209; - DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // Set Power control. (Unknown). + + // Set Power control. + DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + if (_display_id == PANEL_INL_2J055IA_27A) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else if (_display_id == PANEL_AUO_A055TAN01) + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + else // PANEL_V40_55_UNK. + DSI(_DSIREG(DSI_WR_DATA)) = 0x731348B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT3 / XDK, VRH gamma volt adj 51 / x40). + if (_display_id == PANEL_INL_2J055IA_27A || _display_id == PANEL_AUO_A055TAN01) + { + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // (Unknown). + } + else // PANEL_V40_55_UNK. + { + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/48, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71243209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x004C31; // (Unknown). + } DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; usleep(5000); break; + case PANEL_INL_P062CCA_AZ1: default: break; } + // Blank - powerdown. _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, 50000); - // Disable display and backlight pins. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. +skip_panel_deinit: + // Disable LCD power pins. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); // LCD Reset disable. usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); // LCD -5V disable. usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); // LCD +5V disable. usleep(10000); // Disable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); // Power down pads. DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; - // Switch to automatic function mode. + // Switch LCD PWM backlight pin to special function mode and enable PWM0 mode. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode. +} + +void display_end() { _display_panel_and_hw_end(false); }; + +u16 display_get_decoded_lcd_id() +{ + return _display_id; } void display_color_screen(u32 color) @@ -378,7 +662,7 @@ u32 *display_init_framebuffer_log() void display_activate_console() { - DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window D. DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = WIN_ENABLE; // Enable window DD. DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0xFF80; DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; @@ -399,7 +683,7 @@ void display_activate_console() void display_deactivate_console() { - DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window D. for (u32 i = 0xFFFF; i > 0xFF7F; i--) { diff --git a/bdk/gfx/di.h b/bdk/gfx/di.h index 2723de0..e304fb6 100644 --- a/bdk/gfx/di.h +++ b/bdk/gfx/di.h @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,9 @@ #include #include +#define DSI_VIDEO_DISABLED 0 +#define DSI_VIDEO_ENABLED 1 + /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) @@ -42,11 +45,11 @@ #define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 -#define SYNCPT_CNTRL_NO_STALL (1 << 8) -#define SYNCPT_CNTRL_SOFT_RESET (1 << 0) +#define SYNCPT_CNTRL_SOFT_RESET BIT(0) +#define SYNCPT_CNTRL_NO_STALL BIT(8) #define DC_CMD_CONT_SYNCPT_VSYNC 0x28 -#define SYNCPT_VSYNC_ENABLE (1 << 8) +#define SYNCPT_VSYNC_ENABLE BIT(8) #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 @@ -57,42 +60,43 @@ #define DISP_CTRL_MODE_MASK (3 << 5) #define DC_CMD_DISPLAY_POWER_CONTROL 0x36 -#define PW0_ENABLE (1 << 0) -#define PW1_ENABLE (1 << 2) -#define PW2_ENABLE (1 << 4) -#define PW3_ENABLE (1 << 6) -#define PW4_ENABLE (1 << 8) -#define PM0_ENABLE (1 << 16) -#define PM1_ENABLE (1 << 18) +#define PW0_ENABLE BIT(0) +#define PW1_ENABLE BIT(2) +#define PW2_ENABLE BIT(4) +#define PW3_ENABLE BIT(6) +#define PW4_ENABLE BIT(8) +#define PM0_ENABLE BIT(16) +#define PM1_ENABLE BIT(18) #define DC_CMD_INT_STATUS 0x37 #define DC_CMD_INT_MASK 0x38 #define DC_CMD_INT_ENABLE 0x39 +#define DC_CMD_INT_FRAME_END_INT BIT(1) #define DC_CMD_STATE_ACCESS 0x40 -#define READ_MUX (1 << 0) -#define WRITE_MUX (1 << 2) +#define READ_MUX BIT(0) +#define WRITE_MUX BIT(2) #define DC_CMD_STATE_CONTROL 0x41 -#define GENERAL_ACT_REQ (1 << 0) -#define WIN_A_ACT_REQ (1 << 1) -#define WIN_B_ACT_REQ (1 << 2) -#define WIN_C_ACT_REQ (1 << 3) -#define WIN_D_ACT_REQ (1 << 4) -#define CURSOR_ACT_REQ (1 << 7) -#define GENERAL_UPDATE (1 << 8) -#define WIN_A_UPDATE (1 << 9) -#define WIN_B_UPDATE (1 << 10) -#define WIN_C_UPDATE (1 << 11) -#define WIN_D_UPDATE (1 << 12) -#define CURSOR_UPDATE (1 << 15) -#define NC_HOST_TRIG (1 << 24) +#define GENERAL_ACT_REQ BIT(0) +#define WIN_A_ACT_REQ BIT(1) +#define WIN_B_ACT_REQ BIT(2) +#define WIN_C_ACT_REQ BIT(3) +#define WIN_D_ACT_REQ BIT(4) +#define CURSOR_ACT_REQ BIT(7) +#define GENERAL_UPDATE BIT(8) +#define WIN_A_UPDATE BIT(9) +#define WIN_B_UPDATE BIT(10) +#define WIN_C_UPDATE BIT(11) +#define WIN_D_UPDATE BIT(12) +#define CURSOR_UPDATE BIT(15) +#define NC_HOST_TRIG BIT(24) #define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 -#define WINDOW_A_SELECT (1 << 4) -#define WINDOW_B_SELECT (1 << 5) -#define WINDOW_C_SELECT (1 << 6) -#define WINDOW_D_SELECT (1 << 7) +#define WINDOW_A_SELECT BIT(4) +#define WINDOW_B_SELECT BIT(5) +#define WINDOW_C_SELECT BIT(6) +#define WINDOW_D_SELECT BIT(7) #define DC_CMD_REG_ACT_CONTROL 0x043 @@ -125,12 +129,13 @@ // DC_DISP shadowed registers. #define DC_DISP_DISP_WIN_OPTIONS 0x402 -#define HDMI_ENABLE (1 << 30) -#define DSI_ENABLE (1 << 29) -#define SOR1_TIMING_CYA (1 << 27) -#define SOR1_ENABLE (1 << 26) -#define SOR_ENABLE (1 << 25) -#define CURSOR_ENABLE (1 << 16) +#define CURSOR_ENABLE BIT(16) +#define SOR_ENABLE BIT(25) +#define SOR1_ENABLE BIT(26) +#define SOR1_TIMING_CYA BIT(27) +#define DSI_ENABLE BIT(29) +#define HDMI_ENABLE BIT(30) + #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 @@ -142,6 +147,7 @@ #define DC_DISP_FRONT_PORCH 0x40A #define DC_DISP_DISP_CLOCK_CONTROL 0x42E +#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) @@ -155,7 +161,6 @@ #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) -#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) #define DC_DISP_DISP_INTERFACE_CONTROL 0x42F #define DISP_DATA_FORMAT_DF1P1C (0 << 0) @@ -189,8 +194,8 @@ #define BASE_COLOR_SIZE_888 (8 << 0) #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 -#define SC1_H_QUALIFIER_NONE (1 << 16) -#define SC0_H_QUALIFIER_NONE (1 << 0) +#define SC0_H_QUALIFIER_NONE BIT(0) +#define SC1_H_QUALIFIER_NONE BIT(16) #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 #define DE_SELECT_ACTIVE_BLANK (0 << 0) @@ -217,6 +222,7 @@ #define CURSOR_SIZE_128 (2 << 24) #define CURSOR_SIZE_256 (3 << 24) #define DC_DISP_CURSOR_POSITION 0x440 +#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_DISP_CURSOR_START_ADDR_HI 0x4EC #define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1 #define CURSOR_BLEND_2BIT (0 << 24) @@ -247,12 +253,12 @@ // The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). #define DC_WIN_WIN_OPTIONS 0x700 -#define H_DIRECTION (1 << 0) -#define V_DIRECTION (1 << 2) -#define SCAN_COLUMN (1 << 4) -#define COLOR_EXPAND (1 << 6) -#define CSC_ENABLE (1 << 18) -#define WIN_ENABLE (1 << 30) +#define H_DIRECTION BIT(0) +#define V_DIRECTION BIT(2) +#define SCAN_COLUMN BIT(4) +#define COLOR_EXPAND BIT(6) +#define CSC_ENABLE BIT(18) +#define WIN_ENABLE BIT(30) #define DC_WIN_BUFFER_CONTROL 0x702 #define BUFFER_CONTROL_HOST 0 @@ -358,6 +364,10 @@ /*! Display serial interface registers. */ #define _DSIREG(reg) ((reg) * 4) +#define DSI_INCR_SYNCPT_CNTRL 0x1 +#define DSI_INCR_SYNCPT_SOFT_RESET BIT(0) +#define DSI_INCR_SYNCPT_NO_STALL BIT(8) + #define DSI_RD_DATA 0x9 #define DSI_WR_DATA 0xA @@ -369,39 +379,42 @@ #define DSI_INT_MASK 0xE #define DSI_HOST_CONTROL 0xF -#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) -#define DSI_HOST_CONTROL_CRC_RESET (1 << 20) +#define DSI_HOST_CONTROL_ECC BIT(0) +#define DSI_HOST_CONTROL_CS BIT(1) +#define DSI_HOST_CONTROL_PKT_BTA BIT(2) +#define DSI_HOST_CONTROL_IMM_BTA BIT(3) +#define DSI_HOST_CONTROL_FIFO_SEL BIT(4) +#define DSI_HOST_CONTROL_HS BIT(5) +#define DSI_HOST_CONTROL_RAW BIT(6) #define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) #define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) #define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) -#define DSI_HOST_CONTROL_RAW (1 << 6) -#define DSI_HOST_CONTROL_HS (1 << 5) -#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) -#define DSI_HOST_CONTROL_IMM_BTA (1 << 3) -#define DSI_HOST_CONTROL_PKT_BTA (1 << 2) -#define DSI_HOST_CONTROL_CS (1 << 1) -#define DSI_HOST_CONTROL_ECC (1 << 0) +#define DSI_HOST_CONTROL_CRC_RESET BIT(20) +#define DSI_HOST_CONTROL_FIFO_RESET BIT(21) #define DSI_CONTROL 0x10 -#define DSI_CONTROL_HS_CLK_CTRL (1 << 20) -#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) -#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) -#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) -#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) -#define DSI_CONTROL_DCS_ENABLE (1 << 3) +#define DSI_CONTROL_HOST_ENABLE BIT(0) +#define DSI_CONTROL_VIDEO_ENABLE BIT(1) #define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) -#define DSI_CONTROL_VIDEO_ENABLE (1 << 1) -#define DSI_CONTROL_HOST_ENABLE (1 << 0) +#define DSI_CONTROL_DCS_ENABLE BIT(3) +#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) +#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) +#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) +#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) +#define DSI_CONTROL_HS_CLK_CTRL BIT(20) #define DSI_SOL_DELAY 0x11 #define DSI_MAX_THRESHOLD 0x12 #define DSI_TRIGGER 0x13 -#define DSI_TRIGGER_HOST (1 << 1) -#define DSI_TRIGGER_VIDEO (1 << 0) +#define DSI_TRIGGER_VIDEO BIT(0) +#define DSI_TRIGGER_HOST BIT(1) #define DSI_TX_CRC 0x14 + #define DSI_STATUS 0x15 +#define DSI_STATUS_RX_FIFO_SIZE 0x1F + #define DSI_INIT_SEQ_CONTROL 0x1A #define DSI_INIT_SEQ_DATA_0 0x1B #define DSI_INIT_SEQ_DATA_1 0x1C @@ -430,36 +443,53 @@ #define DSI_BTA_TIMING 0x3F #define DSI_TIMEOUT_0 0x44 -#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) +#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_1 0x45 -#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) +#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) #define DSI_TO_TALLY 0x46 #define DSI_PAD_CONTROL_0 0x4B -#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) -#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) -#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) +#define DSI_PAD_CONTROL_VS1_PDIO_CLK BIT(8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) +#define DSI_PAD_CONTROL_VS1_PULLDN_CLK BIT(24) +#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) #define DSI_PAD_CONTROL_CD 0x4C #define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_CMD_PKT_VID_ENABLE 1 +#define DSI_DSI_LINE_TYPE(x) ((x) << 1) #define DSI_PAD_CONTROL_1 0x4F #define DSI_PAD_CONTROL_2 0x50 #define DSI_PAD_CONTROL_3 0x51 -#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) -#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) -#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) #define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) +#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) +#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) +#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) #define DSI_PAD_CONTROL_4 0x52 +#define DSI_PAD_CONTROL_5_B01 0x53 +#define DSI_PAD_CONTROL_6_B01 0x54 +#define DSI_PAD_CONTROL_7_B01 0x55 #define DSI_INIT_SEQ_DATA_15 0x5F +#define DSI_INIT_SEQ_DATA_15_B01 0x62 + +/*! DSI packet defines */ +#define DSI_ESCAPE_CMD 0x87 +#define DSI_ACK_NO_ERR 0x84 + +#define ACK_ERROR_RES 0x02 +#define GEN_LONG_RD_RES 0x1A +#define DCS_LONG_RD_RES 0x1C +#define GEN_1_BYTE_SHORT_RD_RES 0x11 +#define DCS_1_BYTE_SHORT_RD_RES 0x21 +#define GEN_2_BYTE_SHORT_RD_RES 0x12 +#define DCS_2_BYTE_SHORT_RD_RES 0x22 /*! MIPI registers. */ #define MIPI_CAL_MIPI_CAL_CTRL (0x00 / 0x4) @@ -483,25 +513,168 @@ #define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4) /*! MIPI CMDs. */ -#define MIPI_DSI_DCS_SHORT_WRITE 0x05 -#define MIPI_DSI_DCS_READ 0x06 -#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 +#define MIPI_DSI_V_SYNC_START 0x01 +#define MIPI_DSI_COLOR_MODE_OFF 0x02 +#define MIPI_DSI_END_OF_TRANSMISSION 0x08 +#define MIPI_DSI_NULL_PACKET 0x09 +#define MIPI_DSI_V_SYNC_END 0x11 +#define MIPI_DSI_COLOR_MODE_ON 0x12 +#define MIPI_DSI_BLANKING_PACKET 0x19 +#define MIPI_DSI_H_SYNC_START 0x21 +#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22 +#define MIPI_DSI_H_SYNC_END 0x31 +#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32 #define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37 -#define MIPI_DSI_DCS_LONG_WRITE 0x39 + +#define MIPI_DSI_DCS_SHORT_WRITE 0x05 +#define MIPI_DSI_DCS_READ 0x06 +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 +#define MIPI_DSI_DCS_LONG_WRITE 0x39 + +#define MIPI_DSI_GENERIC_LONG_WRITE 0x29 +#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03 +#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13 +#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23 +#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04 +#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14 +#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24 /*! MIPI DCS CMDs. */ -#define MIPI_DCS_GET_DISPLAY_ID 0x04 -#define MIPI_DCS_ENTER_SLEEP_MODE 0x10 -#define MIPI_DCS_EXIT_SLEEP_MODE 0x11 -#define MIPI_DCS_SET_DISPLAY_ON 0x29 +#define MIPI_DCS_NOP 0x00 +#define MIPI_DCS_SOFT_RESET 0x01 +#define MIPI_DCS_GET_COMPRESSION_MODE 0x03 +#define MIPI_DCS_GET_DISPLAY_ID 0x04 +#define MIPI_DCS_GET_DISPLAY_ID1 0xDA // GET_DISPLAY_ID Byte0, Module Manufacturer ID. +#define MIPI_DCS_GET_DISPLAY_ID2 0xDB // GET_DISPLAY_ID Byte1, Module/Driver Version ID. +#define MIPI_DCS_GET_DISPLAY_ID3 0xDC // GET_DISPLAY_ID Byte2, Module/Driver ID. +#define MIPI_DCS_GET_NUM_ERRORS 0x05 +#define MIPI_DCS_GET_RED_CHANNEL 0x06 +#define MIPI_DCS_GET_GREEN_CHANNEL 0x07 +#define MIPI_DCS_GET_BLUE_CHANNEL 0x08 +#define MIPI_DCS_GET_DISPLAY_STATUS 0x09 +#define MIPI_DCS_GET_POWER_MODE 0x0A +#define MIPI_DCS_GET_ADDRESS_MODE 0x0B +#define MIPI_DCS_GET_PIXEL_FORMAT 0x0C +#define MIPI_DCS_GET_DISPLAY_MODE 0x0D +#define MIPI_DCS_GET_SIGNAL_MODE 0x0E +#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0F +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10 +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11 +#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12 +#define MIPI_DCS_ENTER_NORMAL_MODE 0x13 +#define MIPI_DCS_EXIT_INVERT_MODE 0x20 +#define MIPI_DCS_ENTER_INVERT_MODE 0x21 +#define MIPI_DCS_ALL_PIXELS_OFF 0x22 +#define MIPI_DCS_ALL_PIXELS_ON 0x23 +#define MIPI_DCS_SET_CONTRAST 0x25 // VCON in 40mV steps. 7-bit integer. +#define MIPI_DCS_SET_GAMMA_CURVE 0x26 +#define MIPI_DCS_SET_DISPLAY_OFF 0x28 +#define MIPI_DCS_SET_DISPLAY_ON 0x29 +#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2A +#define MIPI_DCS_SET_PAGE_ADDRESS 0x2B +#define MIPI_DCS_WRITE_MEMORY_START 0x2C +#define MIPI_DCS_WRITE_LUT 0x2D // 24-bit: 192 bytes. +#define MIPI_DCS_READ_MEMORY_START 0x2E +#define MIPI_DCS_SET_PARTIAL_ROWS 0x30 +#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31 +#define MIPI_DCS_SET_SCROLL_AREA 0x33 +#define MIPI_DCS_SET_TEAR_OFF 0x34 +#define MIPI_DCS_SET_TEAR_ON 0x35 +#define MIPI_DCS_SET_ADDRESS_MODE 0x36 +#define MIPI_DCS_SET_SCROLL_START 0x37 +#define MIPI_DCS_EXIT_IDLE_MODE 0x38 +#define MIPI_DCS_ENTER_IDLE_MODE 0x39 +#define MIPI_DCS_SET_PIXEL_FORMAT 0x3A +#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3C +#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3E +#define MIPI_DCS_GET_3D_CONTROL 0x3F +#define MIPI_DCS_SET_VSYNC_TIMING 0x40 +#define MIPI_DCS_SET_TEAR_SCANLINE 0x44 +#define MIPI_DCS_GET_SCANLINE 0x45 +#define MIPI_DCS_SET_TEAR_SCANLINE_WIDTH 0x46 +#define MIPI_DCS_GET_SCANLINE_WIDTH 0x47 +#define MIPI_DCS_SET_BRIGHTNESS 0x51 // DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL. +#define MIPI_DCS_GET_BRIGHTNESS 0x52 +#define MIPI_DCS_SET_CONTROL_DISPLAY 0x53 +#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54 +#define MIPI_DCS_SET_CABC_VALUE 0x55 +#define MIPI_DCS_GET_CABC_VALUE 0x56 +#define MIPI_DCS_SET_CABC_MIN_BRI 0x5E +#define MIPI_DCS_GET_CABC_MIN_BRI 0x5F +#define MIPI_DCS_READ_DDB_START 0xA1 +#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 + +/*! MIPI DCS Panel Private CMDs. */ +#define MIPI_DCS_PRIV_UNK_A0 0xA0 +#define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1 +#define MIPI_DCS_PRIV_SET_EXTC 0xB9 +#define MIPI_DCS_PRIV_UNK_BD 0xBD +#define MIPI_DCS_PRIV_UNK_D5 0xD5 +#define MIPI_DCS_PRIV_UNK_D6 0xD6 +#define MIPI_DCS_PRIV_UNK_D8 0xD8 +#define MIPI_DCS_PRIV_UNK_D9 0xD9 + +/*! MIPI DCS CMD Defines. */ +#define DCS_POWER_MODE_DISPLAY_ON BIT(2) +#define DCS_POWER_MODE_NORMAL_MODE BIT(3) +#define DCS_POWER_MODE_SLEEP_MODE BIT(4) +#define DCS_POWER_MODE_PARTIAL_MODE BIT(5) +#define DCS_POWER_MODE_IDLE_MODE BIT(6) + +#define DCS_ADDRESS_MODE_V_FLIP BIT(0) +#define DCS_ADDRESS_MODE_H_FLIP BIT(1) +#define DCS_ADDRESS_MODE_LATCH_RL BIT(2) // Latch Data Order. +#define DCS_ADDRESS_MODE_BGR_COLOR BIT(3) +#define DCS_ADDRESS_MODE_LINE_ORDER BIT(4) // Line Refresh Order. +#define DCS_ADDRESS_MODE_SWAP_XY BIT(5) // Page/Column Addressing Reverse Order. +#define DCS_ADDRESS_MODE_MIRROR_X BIT(6) // Column Address Order. +#define DCS_ADDRESS_MODE_MIRROR_Y BIT(7) // Page Address Order. +#define DCS_ADDRESS_MODE_ROTATION_MASK (0xF << 4) +#define DCS_ADDRESS_MODE_ROTATION_90 (DCS_ADDRESS_MODE_SWAP_XY | DCS_ADDRESS_MODE_LINE_ORDER) +#define DCS_ADDRESS_MODE_ROTATION_180 (DCS_ADDRESS_MODE_MIRROR_X | DCS_ADDRESS_MODE_LINE_ORDER) +#define DCS_ADDRESS_MODE_ROTATION_270 (DCS_ADDRESS_MODE_SWAP_XY) + +#define DCS_GAMMA_CURVE_NONE 0 +#define DCS_GAMMA_CURVE_GC0_1_8 BIT(0) +#define DCS_GAMMA_CURVE_GC1_2_5 BIT(1) +#define DCS_GAMMA_CURVE_GC2_1_0 BIT(2) +#define DCS_GAMMA_CURVE_GC3_1_0 BIT(3) // Are there more? + +#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL BIT(2) +#define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) +#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5) /* Switch Panels: + * + * 6.2" panels for Icosa and Iowa skus: * [10] 81 [26]: JDI LPM062M326A * [10] 96 [09]: JDI LAM062M109A * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) - * [20] XX [10]: InnoLux P062CCA-AZ2 [UNCONFIRMED ID] + * [20] 95 [0F]: InnoLux P062CCA-AZ2 * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) - * [30] XX [10]: AUO A062TAN02 (59.06A33.002) [UNCONFIRMED ID] + * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002) + * + * 5.5" panels for Hoag skus: + * [20] 94 [10]: InnoLux 2J055IA-27A (Rev B1) + * [30] XX [10]: AUO A055TAN01 (59.05A30.001) [UNCONFIRMED ID] + * [40] XX [10]: Vendor 40 [UNCONFIRMED ID] + */ + +/* Display ID Decoding: + * + * byte0: Vendor + * byte1: Model + * byte2: Board + * + * Vendors: + * 10h: Japan Display Inc. + * 20h: InnoLux Corporation + * 30h: AU Optronics + * 40h: Unknown1 + * + * Boards, Panel Size: + * 0Fh: Icosa/Iowa, 6.2" + * 10h: Hoag, 5.5" */ enum @@ -511,14 +684,18 @@ enum PANEL_JDI_LPM062M326A = 0x2610, PANEL_INL_P062CCA_AZ1 = 0x0F20, PANEL_AUO_A062TAN01 = 0x0F30, - PANEL_INL_P062CCA_AZ2 = 0x1020, - PANEL_AUO_A062TAN02 = 0x1030 + PANEL_INL_2J055IA_27A = 0x1020, + PANEL_AUO_A055TAN01 = 0x1030, + PANEL_V40_55_UNK = 0x1040 }; void display_init(); void display_backlight_pwm_init(); void display_end(); +/*! Get Display panel ID. */ +u16 display_get_decoded_lcd_id(); + /*! Show one single color on the display. */ void display_color_screen(u32 color); @@ -537,4 +714,7 @@ void display_init_cursor(void *crs_fb, u32 size); void display_set_pos_cursor(u32 x, u32 y); void display_deinit_cursor(); +void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled); +int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled); + #endif diff --git a/bdk/gfx/di.inl b/bdk/gfx/di.inl index ef3b1b0..f98c5c7 100644 --- a/bdk/gfx/di.inl +++ b/bdk/gfx/di.inl @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -20,7 +20,7 @@ static const cfg_op_t _display_dc_setup_win_config[94] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_REG_ACT_CONTROL, 0x54}, + {DC_CMD_REG_ACT_CONTROL, 0x54}, // Select H counter for win A/B/C. {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, @@ -96,16 +96,16 @@ static const cfg_op_t _display_dc_setup_win_config[94] = { {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, + {DC_DISP_BLEND_BACKGROUND_COLOR, 0}, {DC_COM_CRC_CONTROL, 0}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, @@ -120,7 +120,7 @@ static const cfg_op_t _display_dc_setup_win_config[94] = { }; //DSI Init config. -static const cfg_op_t _display_dsi_init_config[61] = { +static const cfg_op_t _display_dsi_init_config_part1[8] = { {DSI_WR_DATA, 0}, {DSI_INT_ENABLE, 0}, {DSI_INT_STATUS, 0}, @@ -128,8 +128,9 @@ static const cfg_op_t _display_dsi_init_config[61] = { {DSI_INIT_SEQ_DATA_0, 0}, {DSI_INIT_SEQ_DATA_1, 0}, {DSI_INIT_SEQ_DATA_2, 0}, - {DSI_INIT_SEQ_DATA_3, 0}, - {DSI_INIT_SEQ_DATA_15, 0}, + {DSI_INIT_SEQ_DATA_3, 0} +}; +static const cfg_op_t _display_dsi_init_config_part2[14] = { {DSI_DCS_CMDS, 0}, {DSI_PKT_SEQ_0_LO, 0}, {DSI_PKT_SEQ_1_LO, 0}, @@ -143,7 +144,18 @@ static const cfg_op_t _display_dsi_init_config[61] = { {DSI_PKT_SEQ_3_HI, 0}, {DSI_PKT_SEQ_4_HI, 0}, {DSI_PKT_SEQ_5_HI, 0}, - {DSI_CONTROL, 0}, + {DSI_CONTROL, 0} +}; +static const cfg_op_t _display_dsi_init_config_part3_t210b01[7] = { + {DSI_PAD_CONTROL_1, 0}, + {DSI_PAD_CONTROL_2, 0}, + {DSI_PAD_CONTROL_3, 0}, + {DSI_PAD_CONTROL_4, 0}, + {DSI_PAD_CONTROL_5_B01, 0}, + {DSI_PAD_CONTROL_6_B01, 0}, + {DSI_PAD_CONTROL_7_B01, 0} +}; +static const cfg_op_t _display_dsi_init_config_part4[10] = { {DSI_PAD_CONTROL_CD, 0}, {DSI_SOL_DELAY, 0x18}, {DSI_MAX_THRESHOLD, 0x1E0}, @@ -153,8 +165,9 @@ static const cfg_op_t _display_dsi_init_config[61] = { {DSI_PKT_LEN_2_3, 0}, {DSI_PKT_LEN_4_5, 0}, {DSI_PKT_LEN_6_7, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, + {DSI_PAD_CONTROL_1, 0} +}; +static const cfg_op_t _display_dsi_init_config_part5[12] = { {DSI_PHY_TIMING_1, 0x40A0E05}, {DSI_PHY_TIMING_2, 0x30109}, {DSI_BTA_TIMING, 0x190A14}, @@ -166,8 +179,9 @@ static const cfg_op_t _display_dsi_init_config[61] = { {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {DSI_POWER_CONTROL, 0}, {DSI_POWER_CONTROL, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, + {DSI_PAD_CONTROL_1, 0} +}; +static const cfg_op_t _display_dsi_init_config_part6[14] = { {DSI_PHY_TIMING_1, 0x40A0E05}, {DSI_PHY_TIMING_2, 0x30118}, {DSI_BTA_TIMING, 0x190A14}, @@ -187,12 +201,12 @@ static const cfg_op_t _display_dsi_init_config[61] = { //DSI panel config. static const cfg_op_t _display_init_config_jdi[43] = { {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes. - {DSI_WR_DATA, 0xAAAAAAD8}, + {DSI_WR_DATA, 0xAAAAAAD8}, // Register: 0xD8. {DSI_WR_DATA, 0xAAAAAAEB}, {DSI_WR_DATA, 0xAAEBAAAA}, {DSI_WR_DATA, 0xAAAAAAAA}, @@ -200,10 +214,10 @@ static const cfg_op_t _display_init_config_jdi[43] = { {DSI_WR_DATA, 0xAAEBAAAA}, {DSI_WR_DATA, 0xAA}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x1BD. + {DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 1 to 0xBD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x2739}, // MIPI_DSI_DCS_LONG_WRITE: 39 bytes. - {DSI_WR_DATA, 0xFFFFFFD8}, + {DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8. {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, @@ -214,27 +228,25 @@ static const cfg_op_t _display_init_config_jdi[43] = { {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x2BD. + {DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 2 to 0xBD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0xF39}, // MIPI_DSI_DCS_LONG_WRITE: 15 bytes. - {DSI_WR_DATA, 0xFFFFFFD8}, + {DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8. {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x6D9. + {DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 6 to 0xD9. {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; //DSI packet config. -static const cfg_op_t _display_dsi_packet_config[21] = { - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, +static const cfg_op_t _display_dsi_packet_config[19] = { {DSI_PHY_TIMING_1, 0x40A0E05}, {DSI_PHY_TIMING_2, 0x30172}, {DSI_BTA_TIMING, 0x190A14}, @@ -253,7 +265,7 @@ static const cfg_op_t _display_dsi_packet_config[21] = { {DSI_PKT_LEN_2_3, 0x87001A2}, {DSI_PKT_LEN_4_5, 0x190}, {DSI_PKT_LEN_6_7, 0x190}, - {DSI_HOST_CONTROL, 0}, + {DSI_HOST_CONTROL, 0} }; //DSI mode config. @@ -271,29 +283,44 @@ static const cfg_op_t _display_dsi_mode_config[10] = { }; //MIPI CAL config. -static const cfg_op_t _display_mipi_pad_cal_config[6] = { +static const cfg_op_t _display_mipi_pad_cal_config[4] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0}, - {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, - {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, - {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300} + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0} }; //DSI config. -static const cfg_op_t _display_dsi_pad_cal_config[4] = { +static const cfg_op_t _display_dsi_pad_cal_config_t210[4] = { {DSI_PAD_CONTROL_1, 0}, {DSI_PAD_CONTROL_2, 0}, {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, {DSI_PAD_CONTROL_4, 0} }; +static const cfg_op_t _display_dsi_pad_cal_config_t210b01[7] = { + {DSI_PAD_CONTROL_1, 0}, + {DSI_PAD_CONTROL_2, 0}, + {DSI_PAD_CONTROL_3, 0}, + {DSI_PAD_CONTROL_4, 0x77777}, + {DSI_PAD_CONTROL_5_B01, 0x77777}, + {DSI_PAD_CONTROL_6_B01, 0x1111}, + {DSI_PAD_CONTROL_7_B01, 0} +}; //MIPI CAL config. -static const cfg_op_t _display_mipi_apply_dsi_cal_config[16] = { +static const cfg_op_t _display_mipi_dsi_cal_offsets_config_t210[4] = { {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, - {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002} +}; +static const cfg_op_t _display_mipi_dsi_cal_offsets_config_t210b01[4] = { + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006}, + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000} +}; +static const cfg_op_t _display_mipi_apply_dsi_cal_config[12] = { {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, @@ -372,16 +399,16 @@ static const cfg_op_t _display_video_disp_controller_enable_config[113] = { {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, + {DC_DISP_BLEND_BACKGROUND_COLOR, 0}, {DC_COM_CRC_CONTROL, 0}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, + {DC_WINBUF_BLEND_LAYER_CONTROL, 0x10000FF}, {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, @@ -394,14 +421,37 @@ static const cfg_op_t _display_video_disp_controller_enable_config[113] = { {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_STATE_ACCESS, 0}, - /* Set Display timings */ + + /* Set Display timings + * + * DC_DISP_REF_TO_SYNC: + * V_REF_TO_SYNC - 1 + * H_REF_TO_SYNC - 0 + * + * DC_DISP_SYNC_WIDTH: + * V_SYNC_WIDTH - 1 + * H_SYNC_WIDTH - 72 + * + * DC_DISP_BACK_PORCH: + * V_BACK_PORCH - 9 + * H_BACK_PORCH - 72 + * + * DC_DISP_ACTIVE: + * V_DISP_ACTIVE - 1280 + * H_DISP_ACTIVE - 720 + * + * DC_DISP_FRONT_PORCH: + * V_FRONT_PORCH - 10 + * H_FRONT_PORCH - 136 + */ {DC_DISP_DISP_TIMING_OPTIONS, 0}, - {DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1. + {DC_DISP_REF_TO_SYNC, 0x10000}, {DC_DISP_SYNC_WIDTH, 0x10048}, {DC_DISP_BACK_PORCH, 0x90048}, {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. + {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should happen before DC_DISP_ACTIVE cmd. /* End of Display timings */ + {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, {DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, @@ -477,10 +527,10 @@ static const cfg_op_t _display_dsi_timing_deinit_config[16] = { //DSI config (if ver == 0x10). static const cfg_op_t _display_deinit_config_jdi[22] = { {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x2139}, // MIPI_DSI_DCS_LONG_WRITE: 33 bytes. - {DSI_WR_DATA, 0x191919D5}, + {DSI_WR_DATA, 0x191919D5}, // Register: 0xD5. {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, @@ -491,21 +541,21 @@ static const cfg_op_t _display_deinit_config_jdi[22] = { {DSI_WR_DATA, 0x19}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. - {DSI_WR_DATA, 0x4F0F41B1}, // Set Power control. + {DSI_WR_DATA, 0x4F0F41B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL. {DSI_WR_DATA, 0xF179A433}, {DSI_WR_DATA, 0x002D81}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; static const cfg_op_t _display_deinit_config_auo[37] = { {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. - {DSI_WR_DATA, 0x191919D5}, + {DSI_WR_DATA, 0x191919D5}, // Register: 0xD5. {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, @@ -518,7 +568,7 @@ static const cfg_op_t _display_deinit_config_auo[37] = { {DSI_WR_DATA, 0x19191919}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. - {DSI_WR_DATA, 0x191919D6}, + {DSI_WR_DATA, 0x191919D6}, // Register: 0xD6. {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, @@ -531,13 +581,13 @@ static const cfg_op_t _display_deinit_config_auo[37] = { {DSI_WR_DATA, 0x19191919}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. - {DSI_WR_DATA, 0x711148B1}, // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). - // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + {DSI_WR_DATA, 0x711148B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). {DSI_WR_DATA, 0x71143209}, - {DSI_WR_DATA, 0x114D31}, // Set Power control. (Unknown). + {DSI_WR_DATA, 0x114D31}, // (Unknown). {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. - {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; diff --git a/bdk/input/als.c b/bdk/input/als.c index 99749e2..97d6432 100644 --- a/bdk/input/als.c +++ b/bdk/input/als.c @@ -103,7 +103,8 @@ u8 als_init(als_table_t *als_val) i2c_init(I2C_2); max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD8 | MAX77620_LDO_CFG2_ADE_MASK); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, + (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT | (3 << 3) | MAX77620_LDO_CFG2_ADE_ENABLE)); u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); diff --git a/bdk/input/als.h b/bdk/input/als.h index ad31e42..09adcb6 100644 --- a/bdk/input/als.h +++ b/bdk/input/als.h @@ -45,8 +45,8 @@ #define BH1730_DATA1LOW_REG 0x16 #define BH1730_DATA1HIGH_REG 0x17 -#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | reg) -#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | cmd) +#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg)) +#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd)) typedef struct _als_table_t { diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c index 2db1aa6..9a3e11a 100644 --- a/bdk/input/joycon.c +++ b/bdk/input/joycon.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -33,32 +34,32 @@ // For disabling driver when logging is enabled. #include -#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 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_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_OUTPUT_RPT 0x01 +#define JC_HID_RUMBLE_RPT 0x10 -#define JC_HID_INPUT_RPT 0x30 -#define JC_HID_SUBMCD_RPT 0x21 +#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 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 SPI_READ_OFFSET 0x20 +#define SPI_READ_OFFSET 0x20 #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_BTN_MASK_R 0x0056FF #define JC_ID_L 1 #define JC_ID_R 2 @@ -206,7 +207,7 @@ static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u out->uart_hdr.magic[1] = 0x01; out->uart_hdr.magic[2] = 0x3; - out->uart_hdr.total_size_lsb = 7; + out->uart_hdr.total_size_lsb = sizeof(jc_wired_hdr_t) - sizeof(jc_uart_hdr_t); out->uart_hdr.total_size_msb = 0; out->cmd = wired_cmd; @@ -523,6 +524,9 @@ jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos) u8 retries; jc_bt_conn_t *bt_conn; + if (!jc_init_done) + return NULL; + bt_conn = &jc_gamepad.bt_conn_l; memset(bt_conn->host_mac, 0, 6); memset(bt_conn->ltk, 0, 16); @@ -812,7 +816,10 @@ void jc_init_hw() jc_l.uart = UART_C; jc_r.uart = UART_B; -#if (LV_LOG_PRINTF != 1) + if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG) + return; + +#ifndef DEBUG_UART_PORT jc_power_supply(UART_C, true); jc_power_supply(UART_B, true); diff --git a/bdk/input/touch.c b/bdk/input/touch.c index eef61ec..f24b53a 100644 --- a/bdk/input/touch.c +++ b/bdk/input/touch.c @@ -361,7 +361,7 @@ int touch_power_on() // Enables LDO6 for touchscreen VDD/AVDD supply max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - MAX77620_LDO_CFG2_ADE_ENABLE | (3 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT | (3 << 3) | MAX77620_LDO_CFG2_ADE_ENABLE)); // Configure touchscreen GPIO. PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; diff --git a/bdk/libs/compr/lz.c b/bdk/libs/compr/lz.c index a17c6e4..94b64c6 100644 --- a/bdk/libs/compr/lz.c +++ b/bdk/libs/compr/lz.c @@ -125,7 +125,7 @@ static int _LZ_ReadVarSize( unsigned int * x, const unsigned char * buf ) * insize - Number of input bytes. *************************************************************************/ -void LZ_Uncompress( const unsigned char *in, unsigned char *out, +unsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out, unsigned int insize ) { unsigned char marker, symbol; @@ -134,7 +134,7 @@ void LZ_Uncompress( const unsigned char *in, unsigned char *out, /* Do we have anything to uncompress? */ if( insize < 1 ) { - return; + return 0; } /* Get marker symbol from input stream */ @@ -176,4 +176,6 @@ void LZ_Uncompress( const unsigned char *in, unsigned char *out, } } while( inpos < insize ); + + return outpos; } diff --git a/bdk/libs/compr/lz.h b/bdk/libs/compr/lz.h index 6f31b4a..ef67055 100644 --- a/bdk/libs/compr/lz.h +++ b/bdk/libs/compr/lz.h @@ -41,7 +41,7 @@ extern "C" { * Function prototypes *************************************************************************/ -void LZ_Uncompress( const unsigned char *in, unsigned char *out, +unsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out, unsigned int insize ); diff --git a/bdk/libs/compr/lz4.c b/bdk/libs/compr/lz4.c new file mode 100644 index 0000000..ddea3d8 --- /dev/null +++ b/bdk/libs/compr/lz4.c @@ -0,0 +1,1672 @@ +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ + + +/*-************************************ +* Tuning parameters +**************************************/ +/* + * ACCELERATION_DEFAULT : + * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 + */ +#define ACCELERATION_DEFAULT 1 + + +/*-************************************ +* Dependency +**************************************/ +#define LZ4_STATIC_LINKING_ONLY +#include "lz4.h" +/* see also "memory routines" below */ + + +/*-************************************ +* Compiler Options +**************************************/ +#ifndef LZ4_FORCE_INLINE +# ifdef _MSC_VER /* Visual Studio */ +# define LZ4_FORCE_INLINE static __forceinline +# else +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define LZ4_FORCE_INLINE static inline +# endif +# else +# define LZ4_FORCE_INLINE static +# endif /* __STDC_VERSION__ */ +# endif /* _MSC_VER */ +#endif /* LZ4_FORCE_INLINE */ + +/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE + * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, + * together with a simple 8-byte copy loop as a fall-back path. + * However, this optimization hurts the decompression speed by >30%, + * because the execution does not go to the optimized loop + * for typical compressible data, and all of the preamble checks + * before going to the fall-back path become useless overhead. + * This optimization happens only with the -O3 flag, and -O2 generates + * a simple 8-byte copy loop. + * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy + * functions are annotated with __attribute__((optimize("O2"))), + * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute + * of LZ4_wildCopy does not affect the compression speed. + */ +#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) +# define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2"))) +# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize("O2"))) LZ4_FORCE_INLINE +#else +# define LZ4_FORCE_O2_GCC_PPC64LE +# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) +# define expect(expr,value) (__builtin_expect ((expr),(value)) ) +#else +# define expect(expr,value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + + +/*-************************************ +* Memory routines +**************************************/ +#include /* malloc, calloc, free */ +#define ALLOC(s) malloc(s) +#define ALLOC_AND_ZERO(s) calloc(1,s) +#define FREEMEM free +#include /* memset, memcpy */ +#define MEM_INIT memset + + +/*-************************************ +* Basic Types +**************************************/ +typedef uint16_t U16; +typedef uint32_t U32; +typedef int32_t S32; +typedef uint64_t U64; +typedef uintptr_t uptrval; +typedef size_t reg_t; /* 32-bits in x32 mode */ + +/*-************************************ +* Reading and writing into memory +**************************************/ +static unsigned LZ4_isLittleEndian(void) +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + +static U16 LZ4_read16(const void* memPtr) +{ + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static U32 LZ4_read32(const void* memPtr) +{ + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static void LZ4_write16(void* memPtr, U16 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static void LZ4_write32(void* memPtr, U32 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static U16 LZ4_readLE16(const void* memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } +} + +static void LZ4_writeLE16(void* memPtr, U16 value) +{ + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } +} + +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ +LZ4_FORCE_O2_INLINE_GCC_PPC64LE +void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + + do { memcpy(d,s,8); d+=8; s+=8; } while (d=2) +# include +static int g_debuglog_enable = 1; +# define DEBUGLOG(l, ...) { \ + if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ ": "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } +#else +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + + +/*-************************************ +* Common functions +**************************************/ +static unsigned LZ4_NbCommonBytes (reg_t val) +{ + if (LZ4_isLittleEndian()) { + if (sizeof(val)==8) { + return (__builtin_ctzll((U64)val) >> 3); + } else /* 32 bits */ { + return (__builtin_ctz((U32)val) >> 3); + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { /* 64-bits */ + return (__builtin_clzll((U64)val) >> 3); + } else /* 32 bits */ { + return (__builtin_clz((U32)val) >> 3); + } + } +} + +#define STEPSIZE sizeof(reg_t) +LZ4_FORCE_INLINE +unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; + + if (likely(pIn < pInLimit-(STEPSIZE-1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (!diff) { + pIn+=STEPSIZE; pMatch+=STEPSIZE; + } else { + return LZ4_NbCommonBytes(diff); + } } + + while (likely(pIn < pInLimit-(STEPSIZE-1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } + pIn += LZ4_NbCommonBytes(diff); + return (unsigned)(pIn - pStart); + } + + if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; } + if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; } + if ((pIn compression run slower on incompressible data */ + + +/*-************************************ +* Local Structures and types +**************************************/ +typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; +typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; + +/** + * This enum distinguishes several different modes of accessing previous + * content in the stream. + * + * - noDict : There is no preceding content. + * - withPrefix64k : Table entries up to ctx->dictSize before the current blob + * blob being compressed are valid and refer to the preceding + * content (of length ctx->dictSize), which is available + * contiguously preceding in memory the content currently + * being compressed. + * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere + * else in memory, starting at ctx->dictionary with length + * ctx->dictSize. + * - usingDictCtx : Like usingExtDict, but everything concerning the preceding + * content is in a separate context, pointed to by + * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table + * entries in the current context that refer to positions + * preceding the beginning of the current compression are + * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx + * ->dictSize describe the location and size of the preceding + * content, and matches are found by looking in the ctx + * ->dictCtx->hashTable. + */ +typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; + +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; + + +/*-************************************ +* Local Utils +**************************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } +int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } + + +/*-****************************** +* Compression functions +********************************/ +static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +{ + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +{ + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); +} + +LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) +{ + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); +} + +static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) +{ + switch (tableType) + { + default: /* fallthrough */ + case clearedTable: /* fallthrough */ + case byPtr: { /* illegal! */ return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)idx; return; } + } +} + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case clearedTable: { /* illegal! */ return; } + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + } +} + +LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +/* LZ4_getIndexOnHash() : + * Index of match position registered in hash table. + * hash position must be calculated by using base+index, or dictBase+index. + * Assumption 1 : only valid if tableType == byU32 or byU16. + * Assumption 2 : h is presumed valid (within limits of hash table) + */ +static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) +{ + LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); + if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h]; } + if (tableType == byU16) { const U16* const hashTable = (const U16*) tableBase; return hashTable[h]; } + return 0; /* forbidden case */ +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } + if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ +} + +LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + +LZ4_FORCE_INLINE void LZ4_prepareTable( + LZ4_stream_t_internal* const cctx, + const int inputSize, + const tableType_t tableType) { + /* If the table hasn't been used, it's guaranteed to be zeroed out, and is + * therefore safe to use no matter what mode we're in. Otherwise, we figure + * out if it's safe to leave as is or whether it needs to be reset. + */ + if (cctx->tableType != clearedTable) { + if (cctx->tableType != tableType + || (tableType == byU16 && cctx->currentOffset + inputSize >= 0xFFFFU) + || (tableType == byU32 && cctx->currentOffset > 1 GB) + || tableType == byPtr + || inputSize >= 4 KB) + { + DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); + MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); + cctx->currentOffset = 0; + cctx->tableType = clearedTable; + } else { + DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); + } + } + + /* Adding a gap, so all previous entries are > MAX_DISTANCE back, is faster + * than compressing without a gap. However, compressing with + * currentOffset == 0 is faster still, so we preserve that case. + */ + if (cctx->currentOffset != 0 && tableType == byU32) { + DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); + cctx->currentOffset += 64 KB; + } + + /* Finally, clear history */ + cctx->dictCtx = NULL; + cctx->dictionary = NULL; + cctx->dictSize = 0; +} + +/** LZ4_compress_generic() : + inlined, to ensure branches are decided at compilation time */ +LZ4_FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dictDirective, + const dictIssue_directive dictIssue, + const U32 acceleration) +{ + const BYTE* ip = (const BYTE*) source; + + U32 const startIndex = cctx->currentOffset; + const BYTE* base = (const BYTE*) source - startIndex; + const BYTE* lowLimit; + + const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx; + const BYTE* const dictionary = + dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary; + const U32 dictSize = + dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize; + const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with index in current context */ + + int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); + U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ + const BYTE* const dictEnd = dictionary + dictSize; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; + const BYTE* const matchlimit = iend - LASTLITERALS; + + /* the dictCtx currentOffset is indexed on the start of the dictionary, + * while a dictionary in the current context precedes the currentOffset */ + const BYTE* dictBase = dictDirective == usingDictCtx ? + dictionary + dictSize - dictCtx->currentOffset : /* is it possible that dictCtx->currentOffset != dictCtx->dictSize ? Yes if the dictionary context is not reset */ + dictionary + dictSize - startIndex; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + U32 offset = 0; + U32 forwardH; + + DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType); + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ + + lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0); + + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + + /* Update context state */ + if (dictDirective == usingDictCtx) { + /* Subsequent linked blocks can't use the dictionary. */ + /* Instead, they use the block we just compressed. */ + cctx->dictCtx = NULL; + cctx->dictSize = (U32)inputSize; + } else { + cctx->dictSize += (U32)inputSize; + } + cctx->currentOffset += (U32)inputSize; + cctx->tableType = tableType; + + if (inputSizehashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + if (tableType == byPtr) { + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + + } while ( (match+MAX_DISTANCE < ip) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + + } else { /* byU32, byU16 */ + + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + U32 const current = (U32)(forwardIp - base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + matchIndex += dictDelta; /* make dictCtx index comparable with current context */ + lowLimit = dictionary; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; + } + } else if (dictDirective==usingExtDict) { + if (matchIndex < startIndex) { + DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex); + match = dictBase + matchIndex; + lowLimit = dictionary; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; + } + } else { /* single continuous memory segment */ + match = base + matchIndex; + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); + + if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) continue; /* match outside of valid area */ + if ((tableType != byU16) && (current - matchIndex > MAX_DISTANCE)) continue; /* too far - note: works even if matchIndex overflows */ + + if (LZ4_read32(match) == LZ4_read32(ip)) { + if (maybe_extMem) offset = current - matchIndex; + break; /* match found */ + } + + } while(1); + } + + /* Catch up */ + while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH); + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH); + } + + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) { + op+=4; + LZ4_write32(op, 0xFFFFFFFF); + matchCode -= 4*255; + } + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip >= mflimitPlusOne) break; + + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + + /* Test next position */ + if (tableType == byPtr) { + + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE >= ip) + && (LZ4_read32(match) == LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + } else { /* byU32, byU16 */ + + U32 const h = LZ4_hashPosition(ip, tableType); + U32 const current = (U32)(ip-base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + matchIndex += dictDelta; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else if (dictDirective==usingExtDict) { + if (matchIndex < startIndex) { + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else { /* single memory segment */ + match = base + matchIndex; + } + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); + if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) + && ((tableType==byU16) ? 1 : (current - matchIndex <= MAX_DISTANCE)) + && (LZ4_read32(match) == LZ4_read32(ip)) ) { + token=op++; + *token=0; + if (maybe_extMem) offset = current - matchIndex; + DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source)); + goto _next_match; + } + } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + + } + +_last_literals: + /* Encode Last Literals */ + { size_t const lastRun = (size_t)(iend - anchor); + if ( (outputLimited) && /* Check output buffer overflow */ + ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<internal_donotuse; + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_resetStream((LZ4_stream_t*)state); + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (inputSize < LZ4_64Klimit) {; + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } +} + +/** + * LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. It is only safe + * to call if the state buffer is known to be correctly initialized already + * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of + * "correctly initialized"). + */ +int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) +{ + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + if (dstCapacity >= LZ4_compressBound(srcSize)) { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } +} + + +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + int result; + LZ4_stream_t ctx; + LZ4_stream_t* const ctxPtr = &ctx; + result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + + return result; +} + + +int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); +} + + +/* hidden debug function */ +/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ +int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + LZ4_stream_t ctx; + LZ4_resetStream(&ctx); + + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); +} + + +/*-****************************** +* *_destSize() variant +********************************/ + +static int LZ4_compress_destSize_generic( + LZ4_stream_t_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* base = (const BYTE*) src; + const BYTE* lowLimit = (const BYTE*) src; + const BYTE* anchor = ip; + const BYTE* const iend = ip + *srcSizePtr; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + targetDstSize; + BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; + BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); + BYTE* const oMaxSeq = oMaxLit - 1 /* token */; + + U32 forwardH; + + + /* Init conditions */ + if (targetDstSize < 1) return 0; /* Impossible to store anything */ + if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtrhashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = 1 << LZ4_skipTrigger; + + do { + U32 h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< oMaxMatch) { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { size_t lastRunSize = (size_t)(iend - anchor); + if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } else { + if (*srcSizePtr < LZ4_64Klimit) { + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); + } else { + tableType_t const tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, tableType); + } } +} + + +int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) +{ + LZ4_stream_t ctxBody; + LZ4_stream_t* ctx = &ctxBody; + + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + + return result; +} + + + +/*-****************************** +* Streaming functions +********************************/ + +LZ4_stream_t* LZ4_createStream(void) +{ + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + DEBUGLOG(4, "LZ4_createStream %p", lz4s); + if (lz4s == NULL) return NULL; + LZ4_resetStream(lz4s); + return lz4s; +} + +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ + DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +} + +void LZ4_resetStream_fast(LZ4_stream_t* ctx) { + LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); +} + +int LZ4_freeStream (LZ4_stream_t* LZ4_stream) +{ + if (!LZ4_stream) return 0; /* support free on NULL */ + DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream); + FREEMEM(LZ4_stream); + return (0); +} + + +#define HASH_UNIT sizeof(reg_t) +int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; + const tableType_t tableType = byU32; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); + + LZ4_prepareTable(dict, 0, tableType); + + /* We always increment the offset by 64 KB, since, if the dict is longer, + * we truncate it to the last 64k, and if it's shorter, we still want to + * advance by a whole window length so we can provide the guarantee that + * there are only valid offsets in the window, which allows an optimization + * in LZ4_compress_fast_continue() where it uses noDictIssue even when the + * dictionary isn't a full 64k. */ + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + base = dictEnd - 64 KB - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += 64 KB; + dict->tableType = tableType; + + if (dictSize < (int)HASH_UNIT) { + return 0; + } + + while (p <= dictEnd-HASH_UNIT) { + LZ4_putPosition(p, dict->hashTable, tableType, base); + p+=3; + } + + return dict->dictSize; +} + +void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream) { + if (dictionary_stream != NULL) { + /* If the current offset is zero, we will never look in the + * external dictionary context, since there is no value a table + * entry can take that indicate a miss. In that case, we need + * to bump the offset to something non-zero. + */ + if (working_stream->internal_donotuse.currentOffset == 0) { + working_stream->internal_donotuse.currentOffset = 64 KB; + } + working_stream->internal_donotuse.dictCtx = &(dictionary_stream->internal_donotuse); + } else { + working_stream->internal_donotuse.dictCtx = NULL; + } +} + + +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize) +{ + if (LZ4_dict->currentOffset + nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ + /* rescale hash table */ + U32 const delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + DEBUGLOG(4, "LZ4_renormDictT"); + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } +} + + +int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + const tableType_t tableType = byU32; + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */ + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) { + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); + else + return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration); + } + + /* external dictionary mode */ + { int result; + if (streamPtr->dictCtx) { + /* We depend here on the fact that dictCtx'es (produced by + * LZ4_loadDict) guarantee that their tables contain no references + * to offsets between dictCtx->currentOffset - 64 KB and + * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe + * to use noDictIssue even when the dict isn't a full 64 KB. + */ + if (inputSize > 4 KB) { + /* For compressing large blobs, it is faster to pay the setup + * cost to copy the dictionary's tables into the active context, + * so that the compression loop is only looking into one table. + */ + memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t)); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); + } + } else { + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } + } + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + return result; + } +} + + +/* Hidden debug function, to force-test external dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize) +{ + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; + int result; + + LZ4_renormDictT(streamPtr, srcSize); + + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, dictSmall, 1); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + } + + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)srcSize; + + return result; +} + + +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; + + return dictSize; +} + + + +/*-***************************** +* Decompression functions +*******************************/ +/*! LZ4_decompress_generic() : + * This generic decompression function covers all use cases. + * It shall be instantiated several times, using different sets of directives. + * Note that it is important for performance that this function really get inlined, + * in order to remove useless branches during compilation optimization. + */ +LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_INLINE int LZ4_decompress_generic( + const char* const src, + char* const dst, + int srcSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* const iend = ip + srcSize; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; + const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => just decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((srcSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; + + unsigned const token = *ip++; + + /* shortcut for common case : + * in most circumstances, we expect to decode small matches (<= 18 bytes) separated by few literals (<= 14 bytes). + * this shortcut was tested on x86 and x64, where it improves decoding speed. + * it has not yet been benchmarked on ARM, Power, mips, etc. */ + if (((ip + 14 /*maxLL*/ + 2 /*offset*/ <= iend) + & (op + 14 /*maxLL*/ + 18 /*maxML*/ <= oend)) + & ((token < (15<> ML_BITS; + size_t const off = LZ4_readLE16(ip+ll); + const BYTE* const matchPtr = op + ll - off; /* pointer underflow risk ? */ + if ((off >= 8) /* do not deal with overlapping matches */ & (matchPtr >= lowPrefix)) { + size_t const ml = (token & ML_MASK) + MINMATCH; + memcpy(op, ip, 16); op += ll; ip += ll + 2 /*offset*/; + memcpy(op + 0, matchPtr + 0, 8); + memcpy(op + 8, matchPtr + 8, 8); + memcpy(op +16, matchPtr +16, 2); + op += ml; + continue; + } + } + + /* decode literal length */ + if ((length=(token>>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) + { + if (partialDecoding) { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } else { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += inc32table[offset]; + memcpy(op+4, match, 4); + match -= dec64table[offset]; + } else { memcpy(op, match, 8); match+=8; } + op += 8; + + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op16) LZ4_wildCopy(op+8, match+8, cpy); + } + op = cpy; /* correction */ + } + + /* end of decoding */ + if (endOnInput) + return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ + else + return (int) (((const char*)ip)-src); /* Nb of input bytes read */ + + /* Overflow error detected */ +_output_error: + return (int) (-(((const char*)ip)-src))-1; +} + + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); +} + + +/*===== streaming decompression functions =====*/ + +LZ4_streamDecode_t* LZ4_createStreamDecode(void) +{ + LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); + return lz4s; +} + +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) +{ + if (!LZ4_stream) return 0; /* support free on NULL */ + FREEMEM(LZ4_stream); + return 0; +} + +/*! + * LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * This function is not necessary if previous data is still available where it was decoded. + * Loading a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; +} + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() +*/ +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ + +LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + + +/*=************************************************* +* Obsolete Functions +***************************************************/ +/* obsolete compression functions */ +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } +int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } +int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } +int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } + +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +int LZ4_resetStreamState(void* state, char* inputBuffer) +{ + (void)inputBuffer; + LZ4_resetStream((LZ4_stream_t*)state); + return 0; +} + +void* LZ4_create (char* inputBuffer) +{ + (void)inputBuffer; + return LZ4_createStream(); +} + +char* LZ4_slideInputBuffer (void* state) +{ + /* avoid const char * -> char * conversion warning */ + return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary; +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +#endif /* LZ4_COMMONDEFS_ONLY */ diff --git a/bdk/libs/compr/lz4.h b/bdk/libs/compr/lz4.h new file mode 100644 index 0000000..0dfa19e --- /dev/null +++ b/bdk/libs/compr/lz4.h @@ -0,0 +1,569 @@ +/* + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef LZ4_H_2983827168210 +#define LZ4_H_2983827168210 + +/* --- Dependency --- */ +#include /* size_t */ + + +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Decompressing an lz4-compressed block also requires metadata (such as compressed size). + Each application is free to encode such metadata in whichever way it wants. + + An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md), + take care of encoding standard metadata alongside LZ4-compressed blocks. + If your application requires interoperability, it's recommended to use it. + A library is provided to take care of it, see lz4frame.h. +*/ + +/*^*************************************************************** +* Export parameters +*****************************************************************/ +/* +* LZ4_DLL_EXPORT : +* Enable exporting of functions when building a Windows DLL +* LZ4LIB_VISIBILITY : +* Control library symbols visibility. +*/ +#ifndef LZ4LIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define LZ4LIB_VISIBILITY +# endif +#endif +#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) +# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY +#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) +# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define LZ4LIB_API LZ4LIB_VISIBILITY +#endif + +/*------ Version ------*/ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 8 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */ + +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) + +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str +#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) + +LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */ +LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; unseful to check dll version */ + + +/*-************************************ +* Tuning parameter +**************************************/ +/*! + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage may improve speed, thanks to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#ifndef LZ4_MEMORY_USAGE +# define LZ4_MEMORY_USAGE 14 +#endif + +/*-************************************ +* Simple Functions +**************************************/ +/*! LZ4_compress_default() : + Compresses 'srcSize' bytes from buffer 'src' + into already allocated 'dst' buffer of size 'dstCapacity'. + Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'src' into a more limited 'dst' budget, + compression stops *immediately*, and the function result is zero. + Note : as a consequence, 'dst' content is not valid. + Note 2 : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer). + srcSize : max supported value is LZ4_MAX_INPUT_SIZE. + dstCapacity : size of buffer 'dst' (which must be already allocated) + return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity) + or 0 if compression fails */ +LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity); + +/*! LZ4_decompress_safe() : + compressedSize : is the exact complete size of the compressed block. + dstCapacity : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity) + If destination buffer is not large enough, decoding will stop and output an error code (negative value). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against malicious data packets. +*/ +LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); + + +/*-************************************ +* Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/*! +LZ4_compressBound() : + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is incorrect (too large or negative) +*/ +LZ4LIB_API int LZ4_compressBound(int inputSize); + +/*! +LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows selection of "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c). +*/ +LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + + +/*! +LZ4_compress_fast_extState() : + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. +*/ +LZ4LIB_API int LZ4_sizeofState(void); +LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + + +/*! +LZ4_compress_destSize() : + Reverse the logic : compresses as much data as possible from 'src' buffer + into already allocated buffer 'dst' of size 'targetDestSize'. + This function either compresses the entire 'src' content into 'dst' if it's large enough, + or fill 'dst' buffer completely with as much data as possible from 'src'. + *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'. + New value is necessarily <= old value. + return : Nb bytes written into 'dst' (necessarily <= targetDestSize) + or 0 if compression fails +*/ +LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize); + + +/*! +LZ4_decompress_fast() : **unsafe!** +This function is a bit faster than LZ4_decompress_safe(), +but doesn't provide any security guarantee. + originalSize : is the uncompressed size to regenerate + Destination buffer must be already allocated, and its size must be >= 'originalSize' bytes. + return : number of bytes read from source buffer (== compressed size). + If the source stream is detected malformed, the function stops decoding and return a negative result. + note : This function respects memory boundaries for *properly formed* compressed data. + However, it does not provide any protection against malicious input. + It also doesn't know 'src' size, and implies it's >= compressed size. + Use this function in trusted environment **only**. +*/ +LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); + +/*! +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'srcSize' at position 'src' + into destination buffer 'dst' of size 'dstCapacity'. + The function will decompress a minimum of 'targetOutputSize' bytes, and stop after that. + However, it's not accurate, and may write more than 'targetOutputSize' (but always <= dstCapacity). + @return : the number of bytes decoded in the destination buffer (necessarily <= dstCapacity) + Note : this number can also be < targetOutputSize, if compressed block contains less data. + Therefore, always control how many bytes were decoded. + If source stream is detected malformed, function returns a negative result. + This function is protected against malicious data packets. +*/ +LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); + + +/*-********************************************* +* Streaming Compression Functions +***********************************************/ +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ + +/*! LZ4_createStream() and LZ4_freeStream() : + * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. + * LZ4_freeStream() releases its memory. + */ +LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); +LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); + +/*! LZ4_resetStream() : + * An LZ4_stream_t structure can be allocated once and re-used multiple times. + * Use this function to start compressing a new stream. + */ +LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); + +/*! LZ4_loadDict() : + * Use this function to load a static dictionary into LZ4_stream_t. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed, and is the same as reset. + * @return : dictionary size, in bytes (necessarily <= 64 KB) + */ +LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); + +/*! LZ4_compress_fast_continue() : + * Compress 'src' content using data from previously compressed blocks, for better compression ratio. + * 'dst' buffer must be already allocated. + * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * + * Important : The previous 64KB of compressed data is assumed to remain present and unmodified in memory! + * + * Special 1 : When input is a double-buffer, they can have any size, including < 64 KB. + * Make sure that buffers are separated by at least one byte. + * This way, each block only depends on previous block. + * Special 2 : If input buffer is a ring-buffer, it can have any size, including < 64 KB. + * + * @return : size of compressed block + * or 0 if there is an error (typically, cannot fit into 'dst'). + * After an error, the stream status is invalid, it can only be reset or freed. + */ +LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_saveDict() : + * If last 64KB data cannot be guaranteed to remain available at its current memory location, + * save it into a safer place (char* safeBuffer). + * This is schematically equivalent to a memcpy() followed by LZ4_loadDict(), + * but is much faster, because LZ4_saveDict() doesn't need to rebuild tables. + * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error. + */ +LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize); + + +/*-********************************************** +* Streaming Decompression Functions +* Bufferless synchronous API +************************************************/ +typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defined later) */ + +/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() : + * creation / destruction of streaming decompression tracking structure. + * A tracking structure can be re-used multiple times sequentially. */ +LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); +LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/*! LZ4_setStreamDecode() : + * An LZ4_streamDecode_t structure can be allocated once and re-used multiple times. + * Use this function to start decompression of a new stream of blocks. + * A dictionary can optionnally be set. Use NULL or size 0 for a reset order. + * @return : 1 if OK, 0 if error + */ +LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/*! LZ4_decompress_*_continue() : + * These decoding functions allow decompression of consecutive blocks in "streaming" mode. + * A block is an unsplittable entity, it must be presented entirely to a decompression function. + * Decompression functions only accept one block at a time. + * The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded. + * If less than 64KB of data has been decoded all the data must be present. + * + * Special : if application sets a ring buffer for decompression, it must respect one of the following conditions : + * - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + * In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + * - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + * maxBlockSize is implementation dependent. It's the maximum size of any single block. + * In which case, encoding and decoding buffers do not need to be synchronized, + * and encoding ring buffer can have any size, including small ones ( < 64 KB). + * - _At least_ 64 KB + 8 bytes + maxBlockSize. + * In which case, encoding and decoding buffers do not need to be synchronized, + * and encoding ring buffer can have any size, including larger than decoding buffer. + * Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + * and indicate where it is saved using LZ4_setStreamDecode() before decompressing next block. +*/ +LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity); +LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize); + + +/*! LZ4_decompress_*_usingDict() : + * These decoding functions work the same as + * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue() + * They are stand-alone, and don't need an LZ4_streamDecode_t structure. + */ +LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize); +LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize); + + +/*^********************************************** + * !!!!!! STATIC LINKING ONLY !!!!!! + ***********************************************/ + +/*-************************************ + * Unstable declarations + ************************************** + * Declarations in this section should be considered unstable. + * Use at your own peril, etc., etc. + * They may be removed in the future. + * Their signatures may change. + **************************************/ + +#ifdef LZ4_STATIC_LINKING_ONLY + +/*! LZ4_resetStream_fast() : + * When an LZ4_stream_t is known to be in a internally coherent state, + * it can often be prepared for a new compression with almost no work, only + * sometimes falling back to the full, expensive reset that is always required + * when the stream is in an indeterminate state (i.e., the reset performed by + * LZ4_resetStream()). + * + * LZ4_streams are guaranteed to be in a valid state when: + * - returned from LZ4_createStream() + * - reset by LZ4_resetStream() + * - memset(stream, 0, sizeof(LZ4_stream_t)) + * - the stream was in a valid state and was reset by LZ4_resetStream_fast() + * - the stream was in a valid state and was then used in any compression call + * that returned success + * - the stream was in an indeterminate state and was used in a compression + * call that fully reset the state (LZ4_compress_fast_extState()) and that + * returned success + */ +LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr); + +/*! LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. It is only safe + * to call if the state buffer is known to be correctly initialized already + * (see above comment on LZ4_resetStream_fast() for a definition of "correctly + * initialized"). From a high level, the difference is that this function + * initializes the provided state with a call to LZ4_resetStream_fast() while + * LZ4_compress_fast_extState() starts with a call to LZ4_resetStream(). + */ +LZ4LIB_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_attach_dictionary() : + * This is an experimental API that allows for the efficient use of a + * static dictionary many times. + * + * Rather than re-loading the dictionary buffer into a working context before + * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a + * working LZ4_stream_t, this function introduces a no-copy setup mechanism, + * in which the working stream references the dictionary stream in-place. + * + * Several assumptions are made about the state of the dictionary stream. + * Currently, only streams which have been prepared by LZ4_loadDict() should + * be expected to work. + * + * Alternatively, the provided dictionary stream pointer may be NULL, in which + * case any existing dictionary stream is unset. + * + * If a dictionary is provided, it replaces any pre-existing stream history. + * The dictionary contents are the only history that can be referenced and + * logically immediately precede the data compressed in the first subsequent + * compression call. + * + * The dictionary will only remain attached to the working stream through the + * first compression call, at the end of which it is cleared. The dictionary + * stream (and source buffer) must remain in-place / accessible / unchanged + * through the completion of the first compression call on the stream. + */ +LZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream); + +#endif + +/*-************************************ + * Private definitions + ************************************** + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. + * Using these definitions will expose code to API and/or ABI break in future versions of the library. + **************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ + +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +#include + +typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; +struct LZ4_stream_t_internal { + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint16_t initCheck; + uint16_t tableType; + const uint8_t* dictionary; + const LZ4_stream_t_internal* dictCtx; + uint32_t dictSize; +}; + +typedef struct { + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#else + +typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; +struct LZ4_stream_t_internal { + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned short initCheck; + unsigned short tableType; + const unsigned char* dictionary; + const LZ4_stream_t_internal* dictCtx; + unsigned int dictSize; +}; + +typedef struct { + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#endif + +/*! + * LZ4_stream_t : + * information structure to track an LZ4 stream. + * init this structure before first use. + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * it may change in a future version ! + */ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +union LZ4_stream_u { + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_stream_t */ + + +/*! + * LZ4_streamDecode_t : + * information structure to track an LZ4 stream during decompression. + * init this structure using LZ4_setStreamDecode (or memset()) before first use + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +union LZ4_streamDecode_u { + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_streamDecode_t */ + + +/*-************************************ +* Obsolete Functions +**************************************/ + +/*! Deprecation warnings + Should deprecation warnings be a problem, + it is generally possible to disable them, + typically with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */ +#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ +#else +# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LZ4_DEPRECATED(message) [[deprecated(message)]] +# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (LZ4_GCC_VERSION >= 301) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") +# define LZ4_DEPRECATED(message) +# endif +#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ + +/* Obsolete compression functions */ +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* source, char* dest, int sourceSize); +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* Obsolete decompression functions */ +LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); +LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); + +/* Obsolete streaming functions; degraded functionality; do not use! + * + * In order to perform streaming compression, these functions depended on data + * that is no longer tracked in the state. They have been preserved as well as + * possible: using them will still produce a correct output. However, they don't + * actually retain any history between compression calls. The compression ratio + * achieved will therefore be no better than compressing each chunk + * independently. + */ +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void); +LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); +LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); + +#endif /* LZ4_H_2983827168210 */ + + +#if defined (__cplusplus) +} +#endif diff --git a/bdk/libs/fatfs/diskio.h b/bdk/libs/fatfs/diskio.h index 977124c..6959fb4 100644 --- a/bdk/libs/fatfs/diskio.h +++ b/bdk/libs/fatfs/diskio.h @@ -40,6 +40,7 @@ DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +DRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff); /* Disk Status Bits (DSTATUS) */ @@ -54,6 +55,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define SET_SECTOR_COUNT 1 /* Set media size (needed at FF_USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ diff --git a/bdk/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c index 7217103..9035f35 100644 --- a/bdk/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -38,8 +38,10 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ +#include -#define EFSPRINTF(text, ...) +#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); +//#define EFSPRINTF(...) /*-------------------------------------------------------------------------- @@ -530,7 +532,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } -#define MAX_MALLOC 0x4000 /* Must be >=FF_MAX_SS */ +#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN @@ -590,6 +592,16 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); ---------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/* Print error header */ +/*-----------------------------------------------------------------------*/ + +void print_error() +{ + gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF); +} + + /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ @@ -3894,11 +3906,11 @@ FRESULT f_read ( -#ifdef FF_FASTFS +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Fast Read Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ -#if FF_USE_FASTSEEK + FRESULT f_read_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ @@ -3909,12 +3921,13 @@ FRESULT f_read_fast ( FATFS *fs; UINT csize_bytes; DWORD clst; - DWORD wbytes; - UINT count; + UINT count = 0; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; BYTE *wbuff = (BYTE*)buff; + // TODO support sector reading inside a cluster + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); @@ -3926,17 +3939,6 @@ FRESULT f_read_fast ( if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ csize_bytes = fs->csize * SS(fs); - DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ - - /* If inside a cluster, read the sectors and align to cluster. */ - if (csect) { - wbytes = MIN(btr, (fs->csize - csect) * SS(fs)); - f_read(fp, wbuff, wbytes, (void *)0); - wbuff += wbytes; - btr -= wbytes; - if (!btr) - goto out; - } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ @@ -3944,22 +3946,15 @@ FRESULT f_read_fast ( if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } } - if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ - wbytes = MIN(btr, csize_bytes); sector_base = clst2sect(fs, fp->clust); - count = wbytes / SS(fs); - fp->fptr += wbytes; - btr -= wbytes; - - if (!btr) { /* Final cluster/sectors read. */ - if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); - goto out; - } + count += fs->csize; + btr -= csize_bytes; + fp->fptr += csize_bytes; while (btr) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ @@ -3970,29 +3965,29 @@ FRESULT f_read_fast ( fp->clust = clst; work_sector = clst2sect(fs, fp->clust); - wbytes = MIN(btr, csize_bytes); - if ((work_sector - sector_base) == count) count += wbytes / SS(fs); + if ((work_sector - sector_base) == count) count += fs->csize; else { if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; - count = wbytes / SS(fs); + count = fs->csize; } - fp->fptr += wbytes; - btr -= wbytes; + fp->fptr += MIN(btr, csize_bytes); + btr -= MIN(btr, csize_bytes); + + // TODO: what about if data is smaller than cluster? + // Must read-write back that cluster. if (!btr) { /* Final cluster/sectors read. */ if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); } } -out: LEAVE_FF(fs, FR_OK); } #endif -#endif @@ -4136,11 +4131,11 @@ FRESULT f_write ( -#ifdef FF_FASTFS +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Fast Write Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ -#if FF_USE_FASTSEEK + FRESULT f_write_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ @@ -4151,11 +4146,12 @@ FRESULT f_write_fast ( FATFS *fs; UINT csize_bytes; DWORD clst; - DWORD wbytes; - UINT count; + UINT count = 0; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; - BYTE *wbuff = (BYTE*)buff; + const BYTE *wbuff = (const BYTE*)buff; + + // TODO support sector writing inside a cluster res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { @@ -4170,19 +4166,6 @@ FRESULT f_write_fast ( } csize_bytes = fs->csize * SS(fs); - DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ - - /* If inside a cluster, write the sectors and align to cluster. */ - if (csect) { - wbytes = MIN(btw, (fs->csize - csect) * SS(fs)); - f_write(fp, wbuff, wbytes, (void *)0); - /* Ensure flushing of it. FatFS is not notified for next write if raw. */ - f_sync(fp); - wbuff += wbytes; - btw -= wbytes; - if (!btw) - goto out; - } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ @@ -4192,57 +4175,49 @@ FRESULT f_write_fast ( } if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } - else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ - wbytes = MIN(btw, csize_bytes); sector_base = clst2sect(fs, fp->clust); - count = wbytes / SS(fs); - fp->fptr += wbytes; - btw -= wbytes; - - if (!btw) { /* Final cluster/sectors write. */ - if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= (BYTE)~FA_DIRTY; - goto out; - } + count += fs->csize; + btw -= csize_bytes; + fp->fptr += csize_bytes; while (btw) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } - else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; work_sector = clst2sect(fs, fp->clust); - wbytes = MIN(btw, csize_bytes); - if ((work_sector - sector_base) == count) count += wbytes / SS(fs); + if ((work_sector - sector_base) == count) count += fs->csize; else { if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; - count = wbytes / SS(fs); + count = fs->csize; } - fp->fptr += wbytes; - btw -= wbytes; + fp->fptr += MIN(btw, csize_bytes); + btw -= MIN(btw, csize_bytes); + // what about if data is smaller than cluster? + // Probably must read-write back that cluster. if (!btw) { /* Final cluster/sectors write. */ if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } } -out: fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } #endif -#endif @@ -4703,8 +4678,7 @@ FRESULT f_lseek ( -#ifdef FF_FASTFS -#if FF_USE_FASTSEEK +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ @@ -4712,24 +4686,25 @@ FRESULT f_lseek ( DWORD *f_expand_cltbl ( FIL* fp, /* Pointer to the file object */ UINT tblsz, /* Size of table */ - DWORD *tbl, /* Table pointer */ FSIZE_t ofs /* File pointer from top of file */ ) { if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ - fp->cltbl = (DWORD *)tbl; - fp->cltbl[0] = tblsz; + if (!fp->cltbl) { /* Allocate memory for cluster link table */ + fp->cltbl = (DWORD *)ff_memalloc(tblsz); + fp->cltbl[0] = tblsz; + } if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ - fp->cltbl = (void *)0; + ff_memfree(fp->cltbl); + fp->cltbl = NULL; EFSPRINTF("CLTBLSZ"); - return (void *)0; + return NULL; } f_lseek(fp, 0); return fp->cltbl; } #endif -#endif @@ -5863,7 +5838,7 @@ FRESULT f_mkfs ( UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ @@ -5927,7 +5902,7 @@ FRESULT f_mkfs ( } else { /* Create a single-partition in this function */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } @@ -6151,6 +6126,9 @@ FRESULT f_mkfs ( if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ + if (n % n_fats) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } sz_fat += n / n_fats; } @@ -6214,13 +6192,13 @@ FRESULT f_mkfs ( st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ diff --git a/bdk/libs/fatfs/ff.h b/bdk/libs/fatfs/ff.h index 368ad9d..a83cf63 100644 --- a/bdk/libs/fatfs/ff.h +++ b/bdk/libs/fatfs/ff.h @@ -263,10 +263,8 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ -#ifdef FF_FASTFS FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */ FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */ -#endif FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ @@ -288,9 +286,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -#ifdef FF_FASTFS -DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, DWORD *tbl, FSIZE_t ofs); /* Expand file and populate cluster table */ -#endif +DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ diff --git a/bdk/libs/lv_conf.h b/bdk/libs/lv_conf.h index ab7f311..dcc437d 100644 --- a/bdk/libs/lv_conf.h +++ b/bdk/libs/lv_conf.h @@ -155,7 +155,11 @@ /*Log settings*/ -#define USE_LV_LOG 0 /*Enable/disable the log module*/ +#ifdef DEBUG_UART_PORT +# define USE_LV_LOG 1 /*Enable/disable the log module*/ +#else +# define USE_LV_LOG 0 /*Enable/disable the log module*/ +#endif #if USE_LV_LOG /* How important log should be added: * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information diff --git a/bdk/libs/lvgl/lv_misc/lv_log.c b/bdk/libs/lvgl/lv_misc/lv_log.c index bd59cf3..d2db0c7 100644 --- a/bdk/libs/lvgl/lv_misc/lv_log.c +++ b/bdk/libs/lvgl/lv_misc/lv_log.c @@ -67,7 +67,7 @@ void lv_log_add(lv_log_level_t level, const char * file, int line, const char * static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; char *log = (char *)malloc(0x1000); s_printf(log, "%s: %s \t(%s #%d)\r\n", lvl_prefix[level], dsc, file, line); - uart_send(UART_B, (u8 *)log, strlen(log) + 1); + uart_send(DEBUG_UART_PORT, (u8 *)log, strlen(log) + 1); //gfx_printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line); #else if(print_cb) print_cb(level, file, line, dsc); diff --git a/bdk/mem/emc.h b/bdk/mem/emc.h index 9be6fe8..ea5420a 100644 --- a/bdk/mem/emc.h +++ b/bdk/mem/emc.h @@ -72,6 +72,7 @@ #define EMC_PDEX2MRR 0xb4 #define EMC_ODT_WRITE 0xb0 #define EMC_WEXT 0xb8 +#define EMC_CTT 0xBC #define EMC_RFC_SLR 0xc0 #define EMC_MRS_WAIT_CNT2 0xc4 #define EMC_MRS_WAIT_CNT 0xc8 @@ -86,8 +87,13 @@ #define EMC_MRR 0xec #define EMC_CMDQ 0xf0 #define EMC_MC2EMCQ 0xf4 +#define EMC_FBIO_TWTM 0xF8 +#define EMC_FBIO_TRATM 0xFC +#define EMC_FBIO_TWATM 0x108 +#define EMC_FBIO_TR2REF 0x10C #define EMC_FBIO_SPARE 0x100 #define EMC_FBIO_CFG5 0x104 +#define EMC_FBIO_CFG6 0x114 #define EMC_CFG_RSV 0x120 #define EMC_ACPD_CONTROL 0x124 #define EMC_MPC 0x128 @@ -211,6 +217,7 @@ #define EMC_AUTO_CAL_CONFIG6 0x5cc #define EMC_AUTO_CAL_CONFIG7 0x574 #define EMC_AUTO_CAL_CONFIG8 0x2dc +#define EMC_AUTO_CAL_CONFIG9 0x42C #define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 #define EMC_AUTO_CAL_VREF_SEL_1 0x300 #define EMC_AUTO_CAL_INTERVAL 0x2a8 @@ -232,7 +239,7 @@ #define EMC_COMP_PAD_SW_CTRL 0x57c #define EMC_REQ_CTRL 0x2b0 #define EMC_EMC_STATUS 0x2b4 -#define EMC_STATUS_MRR_DIVLD (1 << 20) +#define EMC_STATUS_MRR_DIVLD BIT(20) #define EMC_CFG_2 0x2b8 #define EMC_CFG_DIG_DLL 0x2bc #define EMC_CFG_DIG_DLL_PERIOD 0x2c0 @@ -386,6 +393,8 @@ #define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 #define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 #define EMC_TRAINING_DRAMC_TIMING 0xedc +#define EMC_PMACRO_DATA_PI_CTRL 0x110 +#define EMC_PMACRO_CMD_PI_CTRL 0x114 #define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 #define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 #define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 @@ -650,6 +659,7 @@ #define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 #define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 #define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 +#define EMC_PMACRO_DSR_VTTGEN_CTRL0 0xC6C #define EMC_PMACRO_BRICK_MAPPING_0 0xc80 #define EMC_PMACRO_BRICK_MAPPING_1 0xc84 #define EMC_PMACRO_BRICK_MAPPING_2 0xc88 @@ -662,6 +672,24 @@ #define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c #define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 #define EMC_PMACRO_TRAINING_CTRL_1 0xcfc +#define EMC_PMACRO_PERBIT_FGCG_CTRL_0 0xD40 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_1 0xD44 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_2 0xD48 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_3 0xD4C +#define EMC_PMACRO_PERBIT_FGCG_CTRL_4 0xD50 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_5 0xD54 +#define EMC_PMACRO_PERBIT_RFU_CTRL_0 0xD60 +#define EMC_PMACRO_PERBIT_RFU_CTRL_1 0xD64 +#define EMC_PMACRO_PERBIT_RFU_CTRL_2 0xD68 +#define EMC_PMACRO_PERBIT_RFU_CTRL_3 0xD6C +#define EMC_PMACRO_PERBIT_RFU_CTRL_4 0xD70 +#define EMC_PMACRO_PERBIT_RFU_CTRL_5 0xD74 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_0 0xD80 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_1 0xD84 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_2 0xD88 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_3 0xD8C +#define EMC_PMACRO_PERBIT_RFU1_CTRL_4 0xD90 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_5 0xD94 #define EMC_PMC_SCRATCH1 0x440 #define EMC_PMC_SCRATCH2 0x444 #define EMC_PMC_SCRATCH3 0x448 @@ -684,10 +712,13 @@ enum typedef struct _emc_mr_data_t { - u8 dev0_ch0; - u8 dev0_ch1; - u8 dev1_ch0; - u8 dev1_ch1; + // Device 0. + u8 rank0_ch0; + u8 rank0_ch1; + + // Device 1. + u8 rank1_ch0; + u8 rank1_ch1; } emc_mr_data_t; #endif diff --git a/bdk/mem/mc.c b/bdk/mem/mc.c index 8a0da1a..cc136dc 100644 --- a/bdk/mem/mc.c +++ b/bdk/mem/mc.c @@ -144,13 +144,12 @@ void mc_disable_ahb_redirect() void mc_enable() { CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - // Enable EMC clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000; - // Enable MC clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1; - // Enable EMC DLL clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset. + // Enable memory clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & ~BIT(CLK_H_EMC)) | BIT(CLK_H_EMC); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & ~BIT(CLK_H_MEM)) | BIT(CLK_H_MEM); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & ~BIT(CLK_X_EMC_DLL)) | BIT(CLK_X_EMC_DLL); + // Clear clock resets for memory. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); usleep(5); //#ifdef CONFIG_ENABLE_AHB_REDIRECT diff --git a/bdk/mem/mc_t210.h b/bdk/mem/mc_t210.h index 87fe2ca..a7a9877 100644 --- a/bdk/mem/mc_t210.h +++ b/bdk/mem/mc_t210.h @@ -461,6 +461,7 @@ #define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c #define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 #define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 +#define MC_UNTRANSLATED_REGION_CHECK 0x948 #define MC_DA_CONFIG0 0x9dc // MC_SECURITY_CARVEOUTX_CFG0 @@ -503,14 +504,14 @@ #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_SEND_CFG_TO_GPU BIT(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_TZ_GLOBAL_WR_EN_BYPASS_CHECK BIT(23) +#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK BIT(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_ALLOW_APERTURE_ID_MISMATCH BIT(25) +#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH BIT(26) -#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27) +#define SEC_CARVEOUT_CFG_IS_WPR BIT(27) #endif diff --git a/bdk/mem/minerva.c b/bdk/mem/minerva.c index 259c63a..183b633 100644 --- a/bdk/mem/minerva.c +++ b/bdk/mem/minerva.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,10 @@ u32 minerva_init() minerva_cfg = NULL; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + //!TODO: Not supported on T210B01 yet. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + return 0; + #ifdef NYX // Set table to nyx storage. mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; @@ -48,7 +53,7 @@ u32 minerva_init() u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); minerva_cfg = (void *)ep_addr; - return 0; + return !minerva_cfg ? 1 : 0; } else { diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c index e58a1eb..aad98db 100644 --- a/bdk/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -20,12 +20,15 @@ #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -33,14 +36,25 @@ #define CONFIG_SDRAM_KEEP_ALIVE +//#define CONFIG_SDRAM_COMPRESS_CFG + +typedef struct _sdram_vendor_patch_t +{ + u32 val; + u32 addr:10; + u32 dramid:22; +} sdram_vendor_patch_t; + #ifdef CONFIG_SDRAM_COMPRESS_CFG -#include -#include "sdram_config_lz.inl" + #include + #include "sdram_config_lz.inl" #else -#include "sdram_config.inl" + #include "sdram_config.inl" #endif -static u32 _get_sdram_id() +#include "sdram_config_t210b01.inl" + +static u32 _sdram_get_id() { return ((fuse_read_odm(4) & 0xF8) >> 3); } @@ -85,17 +99,26 @@ static void _sdram_req_mrr_data(u32 data, bool dual_channel) 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); + + /* + * When a dram chip has only one rank, then the info from the 2 ranks differs. + * Info not matching is only allowed on different channels. + */ + + // Get Device 0 (Rank 0) info from both dram chips (channels). + _sdram_req_mrr_data(BIT(31) | (mrx << 16), EMC_CHAN0); + data.rank0_ch0 = EMC(EMC_MRR) & 0xFF; + data.rank0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); + + // Get Device 1 (Rank 1) info from both dram chips (channels). + _sdram_req_mrr_data(BIT(30) | (mrx << 16), EMC_CHAN1); + data.rank1_ch0 = EMC(EMC_MRR) & 0xFF; + data.rank1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); return data; } -static void _sdram_config(const sdram_params_t *params) +static void _sdram_config_t210(const sdram_params_t210_t *params) { // Program DPD3/DPD4 regs (coldboot path). // Enable sel_dpd on unused pins. @@ -143,9 +166,10 @@ break_nosleep: if (params->clear_clock2_mc1) 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_X_SET) = 0x4000; // Enable EMC_DLL clock. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. + // Enable and clear reset for memory clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); // Set pad macros. EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; @@ -540,7 +564,7 @@ break_nosleep: EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; // Patch BootROM. - if (params->boot_rom_patch_control & (1 << 31)) + if (params->boot_rom_patch_control & BIT(31)) { *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. @@ -695,49 +719,738 @@ break_nosleep: MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; } -#ifndef CONFIG_SDRAM_COMPRESS_CFG -static void _sdram_patch_model_params(u32 dramid, u32 *params) +static void _sdram_config_t210b01(const sdram_params_t210b01_t *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; + u32 pmc_scratch1 = ~params->emc_pmc_scratch1; + u32 pmc_scratch2 = ~params->emc_pmc_scratch2; + + // Override HW FSM if needed. + if (params->clk_rst_pllm_misc20_override_enable) + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = params->clk_rst_pllm_misc20_override; + + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + PMC(APBDEV_PMC_WEAK_BIAS) = (pmc_scratch1 & 0x1000) << 19 | (pmc_scratch1 & 0xFFF) << 18 | (pmc_scratch1 & 0x8000) << 15; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) + 0x80000000; + usleep(params->pmc_io_dpd3_req_wait); + + // Disable e_dpd_vttgen. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | 0x80000000; + usleep(params->pmc_io_dpd4_req_wait); + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | 0x80000000; + usleep(1); + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. + EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; + EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; + EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; + EMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2; + EMC(EMC_CMD_MAPPING_CMD1_0) = params->emc_cmd_mapping_cmd1_0; + EMC(EMC_CMD_MAPPING_CMD1_1) = params->emc_cmd_mapping_cmd1_1; + EMC(EMC_CMD_MAPPING_CMD1_2) = params->emc_cmd_mapping_cmd1_2; + EMC(EMC_CMD_MAPPING_CMD2_0) = params->emc_cmd_mapping_cmd2_0; + EMC(EMC_CMD_MAPPING_CMD2_1) = params->emc_cmd_mapping_cmd2_1; + EMC(EMC_CMD_MAPPING_CMD2_2) = params->emc_cmd_mapping_cmd2_2; + EMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0; + EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; + EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; + EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; + + // Program brick mapping. + EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; + EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1; + EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2; + + // Set pad macros. + EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; + EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; + EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; + + // Set pad macros bias. + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = params->emc_pmacro_bg_bias_ctrl0; + + // Patch 1 to 3 using BCT spare secure variables. + if (params->emc_bct_spare_secure0) + *(vu32 *)params->emc_bct_spare_secure0 = params->emc_bct_spare_secure1; + if (params->emc_bct_spare_secure2) + *(vu32 *)params->emc_bct_spare_secure2 = params->emc_bct_spare_secure3; + if (params->emc_bct_spare_secure4) + *(vu32 *)params->emc_bct_spare_secure4 = params->emc_bct_spare_secure5; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(params->pmc_vddp_sel_wait + 2); // Ensure the regulators settle. + + // Set clock sources. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = params->emc_clock_source; + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; + + // Select EMC write mux. + EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. + if (params->emc_bct_spare2) + *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // This is required to do any reads from the pad macros. + EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. + EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0; + EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1; + EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2; + EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3; + // Set swizzle for Rank 1. + EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0; + EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1; + EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; + EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; + + // Patch 3 using BCT spare variables. + if (params->emc_bct_spare6) + *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Set pad controls. + EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl; + EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; + EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; + + // Program Autocal controls with shadowed register fields. + EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2; + EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; + EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; + EMC(EMC_AUTO_CAL_CONFIG5) = params->emc_auto_cal_config5; + EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6; + EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; + EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; + + EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; + EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; + EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; + EMC(EMC_PMACRO_CMD_TX_DRV) = params->emc_pmacro_cmd_tx_drive; + EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; + EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; + EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; + + EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; + EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; + EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; + + EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0; + EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; + EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; + EMC(EMC_DQS_BRLSHFT_1) = params->emc_dqs_brlshft1; + EMC(EMC_CMD_BRLSHFT_0) = params->emc_cmd_brlshft0; + EMC(EMC_CMD_BRLSHFT_1) = params->emc_cmd_brlshft1; + EMC(EMC_CMD_BRLSHFT_2) = params->emc_cmd_brlshft2; + EMC(EMC_CMD_BRLSHFT_3) = params->emc_cmd_brlshft3; + EMC(EMC_QUSE_BRLSHFT_0) = params->emc_quse_brlshft0; + EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1; + EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; + EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; + + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; + + EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2; + EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; + EMC(EMC_PMACRO_DATA_PAD_RX_CTRL) = params->emc_pmacro_data_pad_rx_ctrl; + EMC(EMC_PMACRO_CMD_PAD_RX_CTRL) = params->emc_pmacro_cmd_pad_rx_ctrl; + EMC(EMC_PMACRO_DATA_PAD_TX_CTRL) = params->emc_pmacro_data_pad_tx_ctrl; + EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode; + EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; + EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl & 0xEFFFFFFF; + + EMC(EMC_CFG_3) = params->emc_cfg3; + EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; + EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; + EMC(EMC_PMACRO_TX_PWRD_2) = params->emc_pmacro_tx_pwrd2; + EMC(EMC_PMACRO_TX_PWRD_3) = params->emc_pmacro_tx_pwrd3; + EMC(EMC_PMACRO_TX_PWRD_4) = params->emc_pmacro_tx_pwrd4; + EMC(EMC_PMACRO_TX_PWRD_5) = params->emc_pmacro_tx_pwrd5; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_0) = params->emc_pmacro_tx_sel_clk_src0; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_1) = params->emc_pmacro_tx_sel_clk_src1; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_2) = params->emc_pmacro_tx_sel_clk_src2; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_3) = params->emc_pmacro_tx_sel_clk_src3; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_4) = params->emc_pmacro_tx_sel_clk_src4; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5; + + // Program per bit pad macros. + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_0) = params->emc_pmacro_perbit_fgcg_ctrl0; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_1) = params->emc_pmacro_perbit_fgcg_ctrl1; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_2) = params->emc_pmacro_perbit_fgcg_ctrl2; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_3) = params->emc_pmacro_perbit_fgcg_ctrl3; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_4) = params->emc_pmacro_perbit_fgcg_ctrl4; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_5) = params->emc_pmacro_perbit_fgcg_ctrl5; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_0) = params->emc_pmacro_perbit_rfu_ctrl0; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_1) = params->emc_pmacro_perbit_rfu_ctrl1; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_2) = params->emc_pmacro_perbit_rfu_ctrl2; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_3) = params->emc_pmacro_perbit_rfu_ctrl3; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_4) = params->emc_pmacro_perbit_rfu_ctrl4; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_5) = params->emc_pmacro_perbit_rfu_ctrl5; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_0) = params->emc_pmacro_perbit_rfu1_ctrl0; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_1) = params->emc_pmacro_perbit_rfu1_ctrl1; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_2) = params->emc_pmacro_perbit_rfu1_ctrl2; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_3) = params->emc_pmacro_perbit_rfu1_ctrl3; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_4) = params->emc_pmacro_perbit_rfu1_ctrl4; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_5) = params->emc_pmacro_perbit_rfu1_ctrl5; + EMC(EMC_PMACRO_DATA_PI_CTRL) = params->emc_pmacro_data_pi_ctrl; + EMC(EMC_PMACRO_CMD_PI_CTRL) = params->emc_pmacro_cmd_pi_ctrl; + + EMC(EMC_PMACRO_DDLL_BYPASS) = params->emc_pmacro_ddll_bypass; + EMC(EMC_PMACRO_DDLL_PWRD_0) = params->emc_pmacro_ddll_pwrd0; + EMC(EMC_PMACRO_DDLL_PWRD_1) = params->emc_pmacro_ddll_pwrd1; + EMC(EMC_PMACRO_DDLL_PWRD_2) = params->emc_pmacro_ddll_pwrd2; + EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0; + EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1; + EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2; + EMC(EMC_PMACRO_IB_VREF_DQ_0) = params->emc_pmacro_ib_vref_dq_0; + EMC(EMC_PMACRO_IB_VREF_DQ_1) = params->emc_pmacro_ib_vref_dq_1; + EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0; + EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1; + EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; + + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_3) = params->emc_pmacro_quse_ddll_rank0_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_4) = params->emc_pmacro_quse_ddll_rank0_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_5) = params->emc_pmacro_quse_ddll_rank0_5; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_0) = params->emc_pmacro_quse_ddll_rank1_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_1) = params->emc_pmacro_quse_ddll_rank1_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_2) = params->emc_pmacro_quse_ddll_rank1_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_3) = params->emc_pmacro_quse_ddll_rank1_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; + + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) = params->emc_pmacro_ob_ddll_long_dq_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4) = params->emc_pmacro_ob_ddll_long_dq_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) = params->emc_pmacro_ob_ddll_long_dq_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0) = params->emc_pmacro_ob_ddll_long_dq_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1) = params->emc_pmacro_ob_ddll_long_dq_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) = params->emc_pmacro_ob_ddll_long_dq_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5; + + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ob_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4) = params->emc_pmacro_ob_ddll_long_dqs_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5) = params->emc_pmacro_ob_ddll_long_dqs_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ob_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ob_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ob_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ob_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4) = params->emc_pmacro_ob_ddll_long_dqs_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5) = params->emc_pmacro_ob_ddll_long_dqs_rank1_5; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ib_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ib_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ib_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ib_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ib_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3; + + EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0; + EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1; + EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; + EMC(EMC_PMACRO_DDLL_LONG_CMD_3) = params->emc_pmacro_ddll_long_cmd_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_4) = params->emc_pmacro_ddll_long_cmd_4; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2; + + // Set DLL periodic offset. + EMC(EMC_PMACRO_DDLL_PERIODIC_OFFSET) = params->emc_pmacro_ddll_periodic_offset; + + // Patch 4 using BCT spare variables. + if (params->emc_bct_spare4) + *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; + + // Patch 4 to 6 using BCT spare secure variables. + if (params->emc_bct_spare_secure6) + *(vu32 *)params->emc_bct_spare_secure6 = params->emc_bct_spare_secure7; + if (params->emc_bct_spare_secure8) + *(vu32 *)params->emc_bct_spare_secure8 = params->emc_bct_spare_secure9; + if (params->emc_bct_spare_secure10) + *(vu32 *)params->emc_bct_spare_secure10 = params->emc_bct_spare_secure11; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + // Initialize MC VPR settings. + MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; + MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi; + MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE) = params->mc_video_protect_vpr_override; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1; + + // Program SDRAM geometry parameters. + MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg; + MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0; + MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1; + MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask; + + // Program bank swizzling. + MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0; + MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1; + MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2; + + // Program external memory aperture (base and size). + MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). + MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom; + MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi; + MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb; + + // Program MTS carveout (base and size). + MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom; + MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi; + MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb; + + // Program the memory arbiter. + MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg; + MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req; + MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl; + MC(MC_EMEM_ARB_REFPB_BANK_CTRL) = params->emc_emem_arb_refpb_bank_ctrl; + MC(MC_EMEM_ARB_TIMING_RCD) = params->mc_emem_arb_timing_rcd; + MC(MC_EMEM_ARB_TIMING_RP) = params->mc_emem_arb_timing_rp; + MC(MC_EMEM_ARB_TIMING_RC) = params->mc_emem_arb_timing_rc; + MC(MC_EMEM_ARB_TIMING_RAS) = params->mc_emem_arb_timing_ras; + MC(MC_EMEM_ARB_TIMING_FAW) = params->mc_emem_arb_timing_faw; + MC(MC_EMEM_ARB_TIMING_RRD) = params->mc_emem_arb_timing_rrd; + MC(MC_EMEM_ARB_TIMING_RAP2PRE) = params->mc_emem_arb_timing_rap2pre; + MC(MC_EMEM_ARB_TIMING_WAP2PRE) = params->mc_emem_arb_timing_wap2pre; + MC(MC_EMEM_ARB_TIMING_R2R) = params->mc_emem_arb_timing_r2r; + MC(MC_EMEM_ARB_TIMING_W2W) = params->mc_emem_arb_timing_w2w; + MC(MC_EMEM_ARB_TIMING_CCDMW) = params->mc_emem_arb_timing_ccdmw; + MC(MC_EMEM_ARB_TIMING_R2W) = params->mc_emem_arb_timing_r2w; + MC(MC_EMEM_ARB_TIMING_W2R) = params->mc_emem_arb_timing_w2r; + MC(MC_EMEM_ARB_TIMING_RFCPB) = params->mc_emem_arb_timing_rfcpb; + MC(MC_EMEM_ARB_DA_TURNS) = params->mc_emem_arb_da_turns; + MC(MC_EMEM_ARB_DA_COVERS) = params->mc_emem_arb_da_covers; + MC(MC_EMEM_ARB_MISC0) = params->mc_emem_arb_misc0; + MC(MC_EMEM_ARB_MISC1) = params->mc_emem_arb_misc1; + MC(MC_EMEM_ARB_MISC2) = params->mc_emem_arb_misc2; + MC(MC_EMEM_ARB_RING1_THROTTLE) = params->mc_emem_arb_ring1_throttle; + MC(MC_EMEM_ARB_OVERRIDE) = params->mc_emem_arb_override; + MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1; + MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; + MC(MC_DA_CONFIG0) = params->mc_da_cfg0; + + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + + // Program second-level clock enable overrides. + MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. + MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. + EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. + EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. + EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0; + EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1; + EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2; + + EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; + EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; + + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; + usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. + if (params->emc_bct_spare8) + *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + EMC(EMC_AUTO_CAL_CONFIG9) = params->emc_auto_cal_config9; + + // Program EMC timing configuration. + EMC(EMC_CFG_2) = params->emc_cfg2; + EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe; + EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1; + EMC(EMC_CFG_PIPE_2) = params->emc_cfg_pipe2; + EMC(EMC_CMDQ) = params->emc_cmd_q; + EMC(EMC_MC2EMCQ) = params->emc_mc2emc_q; + EMC(EMC_MRS_WAIT_CNT) = params->emc_mrs_wait_cnt; + EMC(EMC_MRS_WAIT_CNT2) = params->emc_mrs_wait_cnt2; + EMC(EMC_FBIO_CFG5) = params->emc_fbio_cfg5; + EMC(EMC_RC) = params->emc_rc; + EMC(EMC_RFC) = params->emc_rfc; + EMC(EMC_RFCPB) = params->emc_rfc_pb; + EMC(EMC_REFCTRL2) = params->emc_ref_ctrl2; + EMC(EMC_RFC_SLR) = params->emc_rfc_slr; + EMC(EMC_RAS) = params->emc_ras; + EMC(EMC_RP) = params->emc_rp; + EMC(EMC_TPPD) = params->emc_tppd; + EMC(EMC_CTT) = params->emc_trtm; + EMC(EMC_FBIO_TWTM) = params->emc_twtm; + EMC(EMC_FBIO_TRATM) = params->emc_tratm; + EMC(EMC_FBIO_TWATM) = params->emc_twatm; + EMC(EMC_FBIO_TR2REF) = params->emc_tr2ref; + EMC(EMC_R2R) = params->emc_r2r; + EMC(EMC_W2W) = params->emc_w2w; + EMC(EMC_R2W) = params->emc_r2w; + EMC(EMC_W2R) = params->emc_w2r; + EMC(EMC_R2P) = params->emc_r2p; + EMC(EMC_W2P) = params->emc_w2p; + EMC(EMC_CCDMW) = params->emc_ccdmw; + EMC(EMC_RD_RCD) = params->emc_rd_rcd; + EMC(EMC_WR_RCD) = params->emc_wr_rcd; + EMC(EMC_RRD) = params->emc_rrd; + EMC(EMC_REXT) = params->emc_rext; + EMC(EMC_WEXT) = params->emc_wext; + EMC(EMC_WDV) = params->emc_wdv; + EMC(EMC_WDV_CHK) = params->emc_wdv_chk; + EMC(EMC_WSV) = params->emc_wsv; + EMC(EMC_WEV) = params->emc_wev; + EMC(EMC_WDV_MASK) = params->emc_wdv_mask; + EMC(EMC_WS_DURATION) = params->emc_ws_duration; + EMC(EMC_WE_DURATION) = params->emc_we_duration; + EMC(EMC_QUSE) = params->emc_quse; + EMC(EMC_QUSE_WIDTH) = params->emc_quse_width; + EMC(EMC_IBDLY) = params->emc_ibdly; + EMC(EMC_OBDLY) = params->emc_obdly; + EMC(EMC_EINPUT) = params->emc_einput; + EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration; + EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra; + EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; + EMC(EMC_DBG) = params->emc_dbg; + EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; + EMC(EMC_ISSUE_QRST) = 0; + EMC(EMC_QSAFE) = params->emc_qsafe; + EMC(EMC_RDV) = params->emc_rdv; + EMC(EMC_RDV_MASK) = params->emc_rdv_mask; + EMC(EMC_RDV_EARLY) = params->emc_rdv_early; + EMC(EMC_RDV_EARLY_MASK) = params->emc_rdv_early_mask; + EMC(EMC_QPOP) = params->emc_qpop; + EMC(EMC_REFRESH) = params->emc_refresh; + EMC(EMC_BURST_REFRESH_NUM) = params->emc_burst_refresh_num; + EMC(EMC_PRE_REFRESH_REQ_CNT) = params->emc_prerefresh_req_cnt; + EMC(EMC_PDEX2WR) = params->emc_pdex2wr; + EMC(EMC_PDEX2RD) = params->emc_pdex2rd; + EMC(EMC_PCHG2PDEN) = params->emc_pchg2pden; + EMC(EMC_ACT2PDEN) = params->emc_act2pden; + EMC(EMC_AR2PDEN) = params->emc_ar2pden; + EMC(EMC_RW2PDEN) = params->emc_rw2pden; + EMC(EMC_CKE2PDEN) = params->emc_cke2pden; + EMC(EMC_PDEX2CKE) = params->emc_pdex2che; + EMC(EMC_PDEX2MRR) = params->emc_pdex2mrr; + EMC(EMC_TXSR) = params->emc_txsr; + EMC(EMC_TXSRDLL) = params->emc_txsr_dll; + EMC(EMC_TCKE) = params->emc_tcke; + EMC(EMC_TCKESR) = params->emc_tckesr; + EMC(EMC_TPD) = params->emc_tpd; + EMC(EMC_TFAW) = params->emc_tfaw; + EMC(EMC_TRPAB) = params->emc_trpab; + EMC(EMC_TCLKSTABLE) = params->emc_tclkstable; + EMC(EMC_TCLKSTOP) = params->emc_tclkstop; + EMC(EMC_TREFBW) = params->emc_trefbw; + EMC(EMC_ODT_WRITE) = params->emc_odt_write; + EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll; + EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD; + EMC(EMC_CFG_RSV) = params->emc_cfg_rsv; + EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1; + EMC(EMC_PMC_SCRATCH2) = params->emc_pmc_scratch2; + EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; + EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; + EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; + EMC(EMC_PMACRO_DSR_VTTGEN_CTRL0) = params->emc_pmacro_dsr_vttgen_ctrl0; + + // Set pipe bypass enable bits before sending any DRAM commands. + EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // BootROM patching is used as a generic patch here. + if (params->boot_rom_patch_control) + { + *(vu32 *)params->boot_rom_patch_control = params->boot_rom_patch_data; + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + } + + // Patch 7 to 9 using BCT spare secure variables. + if (params->emc_bct_spare_secure12) + *(vu32 *)params->emc_bct_spare_secure12 = params->emc_bct_spare_secure13; + if (params->emc_bct_spare_secure14) + *(vu32 *)params->emc_bct_spare_secure14 = params->emc_bct_spare_secure15; + if (params->emc_bct_spare_secure16) + *(vu32 *)params->emc_bct_spare_secure16 = params->emc_bct_spare_secure17; + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; + usleep(params->pmc_io_dpd3_req_wait); + + // Set transmission pad control parameters. + EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + + // ZQ CAL setup (not actually issuing ZQ CAL now). + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + if (params->memory_type == MEMORY_TYPE_DDR3L) + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; + if (params->memory_type == MEMORY_TYPE_LPDDR4) + { + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + } + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. + PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFF78007F; + usleep(params->pmc_ddr_ctrl_wait); + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4) + { + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); + } + + if (params->memory_type == MEMORY_TYPE_LPDDR4) + usleep(params->emc_pin_extra_wait + 2000); + else if (params->memory_type == MEMORY_TYPE_DDR3L) + usleep(params->emc_pin_extra_wait + 500); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_program_wait); + + // Send NOP (trigger just needs to be non-zero). + if (params->memory_type != MEMORY_TYPE_LPDDR4) + EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; + + // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. + if (params->memory_type == MEMORY_TYPE_LPDDR2) + usleep(params->emc_pin_extra_wait + 200); + + // Init zq calibration, + if (params->memory_type == MEMORY_TYPE_LPDDR4) + { + // Patch 6 using BCT spare variables. + if (params->emc_bct_spare10) + *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. + EMC(EMC_MRW2) = params->emc_mrw2; + EMC(EMC_MRW) = params->emc_mrw1; + EMC(EMC_MRW3) = params->emc_mrw3; + EMC(EMC_MRW4) = params->emc_mrw4; + EMC(EMC_MRW6) = params->emc_mrw6; + EMC(EMC_MRW14) = params->emc_mrw14; + + EMC(EMC_MRW8) = params->emc_mrw8; + EMC(EMC_MRW12) = params->emc_mrw12; + EMC(EMC_MRW9) = params->emc_mrw9; + EMC(EMC_MRW13) = params->emc_mrw13; + + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + // Issue ZQCAL start, device 0. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; + usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. + if (!(params->emc_dev_select & 2)) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; + usleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; + } + } + } + + // Patch 10 to 12 using BCT spare secure variables. + if (params->emc_bct_spare_secure18) + *(vu32 *)params->emc_bct_spare_secure18 = params->emc_bct_spare_secure19; + if (params->emc_bct_spare_secure20) + *(vu32 *)params->emc_bct_spare_secure20 = params->emc_bct_spare_secure21; + if (params->emc_bct_spare_secure22) + *(vu32 *)params->emc_bct_spare_secure22 = params->emc_bct_spare_secure23; + + // Set package and DPD pad control. + PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). + if (params->memory_type == MEMORY_TYPE_LPDDR2 || params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4) + { + EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + + // Patch 7 using BCT spare variables. + if (params->emc_bct_spare12) + *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + if (params->emc_extra_refresh_num) + EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30); + + // Enable refresh. + EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; + + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; + EMC(EMC_CFG) = params->emc_cfg; + EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq; + EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd; + EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; + + // Write addr swizzle lock bit. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; + + EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. + + EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; + + // Enable EMC pipe clock gating. + EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. + EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; + + // Set untranslated region requirements. + MC(MC_UNTRANSLATED_REGION_CHECK) = params->mc_untranslated_region_check; + + // Lock carveouts per BCT cfg. + MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; + MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; + MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; + + // Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); +} + +#ifndef CONFIG_SDRAM_COMPRESS_CFG +static void _sdram_patch_model_params_t210(u32 dramid, u32 *params) +{ + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210); i++) + if (sdram_cfg_vendor_patches_t210[i].dramid & DRAM_ID(dramid)) + params[sdram_cfg_vendor_patches_t210[i].addr] = sdram_cfg_vendor_patches_t210[i].val; } #endif -sdram_params_t *sdram_get_params() +static void _sdram_patch_model_params_t210b01(u32 dramid, u32 *params) +{ + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210b01); i++) + if (sdram_cfg_vendor_patches_t210b01[i].dramid & DRAM_ID2(dramid)) + params[sdram_cfg_vendor_patches_t210b01[i].addr] = sdram_cfg_vendor_patches_t210b01[i].val; +} + +static void *_sdram_get_params_t210() { // Check if id is proper. - u32 dramid = _get_sdram_id(); + u32 dramid = _sdram_get_id(); if (dramid > 6) dramid = 0; #ifdef CONFIG_SDRAM_COMPRESS_CFG + u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); - return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid]; + return (void *)&buf[sizeof(sdram_params_t210_t) * dramid]; + #else - sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR; - memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t)); + + u32 *buf = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t210_t)); + switch (dramid) { - case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH: - case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT: + case LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH: + case LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT: break; - case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN: - case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH: + case LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE: + case LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH: #ifdef CONFIG_SDRAM_COPPER_SUPPORT - case DRAM_4GB_COPPER_SAMSUNG: - case DRAM_4GB_COPPER_HYNIX: - case DRAM_4GB_COPPER_MICRON: + case LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH: + case LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE: + case LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT: #endif - _sdram_patch_model_params(dramid, (u32 *)buf); + _sdram_patch_model_params_t210(dramid, (u32 *)buf); break; } - return buf; + return (void *)buf; + #endif } +void *sdram_get_params_t210b01() +{ + // Check if id is proper. + u32 dramid = _sdram_get_id(); + if (dramid > 27) + dramid = 8; + + u32 *buf = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(buf, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t)); + + switch (dramid) + { + case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: + case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME: + case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: + case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME: + break; + + case LPDDR4X_IOWA_4GB_SAMSUNG_X1X2: + case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: + case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT: + case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: + case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT: + case LPDDR4X_IOWA_4GB_SAMSUNG_Y: + case LPDDR4X_IOWA_4GB_SAMSUNG_1Y_X: + case LPDDR4X_IOWA_8GB_SAMSUNG_1Y_X: + case LPDDR4X_HOAG_4GB_SAMSUNG_1Y_X: + case LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y: + case LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y: + case LPDDR4X_SDS_4GB_SAMSUNG_1Y_A: + case LPDDR4X_SDS_8GB_SAMSUNG_1Y_X: + case LPDDR4X_SDS_4GB_SAMSUNG_1Y_X: + case LPDDR4X_IOWA_4GB_MICRON_1Y_A: + case LPDDR4X_HOAG_4GB_MICRON_1Y_A: + case LPDDR4X_SDS_4GB_MICRON_1Y_A: + _sdram_patch_model_params_t210b01(dramid, (u32 *)buf); + break; + } + return (void *)buf; +} + /* * Function: sdram_get_params_patched * @@ -754,13 +1467,13 @@ sdram_params_t *sdram_get_params() * Note: The modulus in the header must match and validated. */ -sdram_params_t *sdram_get_params_patched() +void *sdram_get_params_patched() { - #define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff)) - sdram_params_t *sdram_params = sdram_get_params(); + #define IPATCH_CONFIG(addr, data) ((((addr) - 0x100000) / 2) << 16 | ((data) & 0xffff)) + sdram_params_t210_t *sdram_params = _sdram_get_params_t210(); // Disable Warmboot signature check. - sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); + sdram_params->boot_rom_patch_control = BIT(31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); /* // Disable SBK lock. @@ -773,15 +1486,14 @@ sdram_params_t *sdram_get_params_patched() sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); */ - return sdram_params; + return (void *)sdram_params; } -void sdram_init() +static void _sdram_init_t210() { - const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); + const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210(); // Set DRAM voltage. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // VDDP Select. @@ -801,5 +1513,37 @@ void sdram_init() if (params->emc_bct_spare0) *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; - _sdram_config(params); + _sdram_config_t210(params); +} + +static void _sdram_init_t210b01() +{ + const sdram_params_t210b01_t *params = (const sdram_params_t210b01_t *)sdram_get_params_t210b01(); + + // VDDP Select. + PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; + usleep(params->pmc_vddp_sel_wait); + + // Turn on MEM IO Power. + PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power; + PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + + // Patch 1 using BCT spare variables + if (params->emc_bct_spare0) + *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; + + _sdram_config_t210b01(params); +} + +void sdram_init() +{ + // Configure SD regulator for DRAM. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); + + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + _sdram_init_t210(); + else + _sdram_init_t210b01(); } diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h index 620c078..77db819 100644 --- a/bdk/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 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, @@ -18,11 +19,76 @@ #define _SDRAM_H_ #include -#include + +/* + * Tegra X1/X1+ EMC/DRAM Bandwidth Chart: + * + * 40.8 MHz: 0.61 GiB/s + * 68.0 MHz: 1.01 GiB/s + * 102.0 MHz: 1.52 GiB/s + * 204.0 MHz: 3.04 GiB/s <-- Tegra X1/X1+ Init/SC7 Frequency + * 408.0 MHz: 6.08 GiB/s + * 665.6 MHz: 9.92 GiB/s + * 800.0 MHz: 11.92 GiB/s <-- Tegra X1/X1+ Nvidia OS Boot Frequency + * 1065.6 MHz: 15.89 GiB/s + * 1331.2 MHz: 19.84 GiB/s + * 1600.0 MHz: 23.84 GiB/s <-- Tegra X1 Official Max Frequency + * 1862.4 MHz: 27.75 GiB/s <-- Tegra X1+ Official Max Frequency + * 2131.2 MHz: 31.76 GiB/s + * + * Note: BWbits = Hz x bus width x channels = Hz x 64 x 2. + */ + +enum sdram_ids_erista +{ + // LPDDR4 3200Mbps. + LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, + LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, + LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, + LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, + LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, + LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 5, + LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT = 6, +}; + +enum sdram_ids_mariko +{ + // LPDDR4X 3733Mbps. + LPDDR4X_IOWA_4GB_SAMSUNG_X1X2 = 7, + + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, + LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, + LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT = 11, // 4266Mbps. + + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, + LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, + LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT = 15, // 4266Mbps. + + // LPDDR4X 4266Mbps? + LPDDR4X_IOWA_4GB_SAMSUNG_Y = 16, + + LPDDR4X_IOWA_4GB_SAMSUNG_1Y_X = 17, + LPDDR4X_IOWA_8GB_SAMSUNG_1Y_X = 18, + LPDDR4X_HOAG_4GB_SAMSUNG_1Y_X = 19, + + LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y = 20, + LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y = 21, + + LPDDR4X_SDS_4GB_SAMSUNG_1Y_A = 22, + + LPDDR4X_SDS_8GB_SAMSUNG_1Y_X = 23, + LPDDR4X_SDS_4GB_SAMSUNG_1Y_X = 24, + + LPDDR4X_IOWA_4GB_MICRON_1Y_A = 25, + LPDDR4X_HOAG_4GB_MICRON_1Y_A = 26, + LPDDR4X_SDS_4GB_MICRON_1Y_A = 27 +}; void sdram_init(); -sdram_params_t *sdram_get_params(); -sdram_params_t *sdram_get_params_patched(); +void *sdram_get_params_patched(); +void *sdram_get_params_t210b01(); void sdram_lp0_save_params(const void *params); emc_mr_data_t sdram_read_mrx(emc_mr_t mrx); diff --git a/bdk/mem/sdram_config.inl b/bdk/mem/sdram_config.inl index 42e0555..727ec60 100644 --- a/bdk/mem/sdram_config.inl +++ b/bdk/mem/sdram_config.inl @@ -15,26 +15,11 @@ * along with this program. If not, see . */ -#define DRAM_CFG_SIZE 1896 +#define DRAM_CFG_T210_SIZE 1896 -#define DRAM_ID(x) (1 << (x)) +#define DRAM_ID(x) BIT(x) -#define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH 0 -#define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN 1 -#define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2 -#define DRAM_4GB_COPPER_SAMSUNG 3 -#define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH 4 -#define DRAM_4GB_COPPER_HYNIX 5 -#define DRAM_4GB_COPPER_MICRON 6 - -typedef struct _sdram_vendor_patch_t -{ - u32 val; - u16 addr:9; - u16 dramid:7; -} sdram_vendor_patch_t; - -static const sdram_params_t _dram_cfg_0_samsung_4gb = { +static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { /* Specifies the type of memory device */ .memory_type = MEMORY_TYPE_LPDDR4, @@ -112,7 +97,7 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { * DRAM size information * Specifies the value for EMC_ADR_CFG */ - .emc_adr_cfg = 0x00000001, + .emc_adr_cfg = 0x00000001, // 2 populated DRAM Devices. /* * Specifies the time to wait after asserting pin @@ -258,7 +243,7 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { .emc_cfg_dig_dll = 0x002C00A0, .emc_cfg_dig_dll_1 = 0x00003701, .emc_cfg_dig_dll_period = 0x00008000, - .emc_dev_select = 0x00000000, + .emc_dev_select = 0x00000000, // Both devices. .emc_sel_dpd_ctrl = 0x00040008, /* Pads trimmer delays */ @@ -505,9 +490,9 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { .emc_pmacro_cmd_ctrl2 = 0x0A0A0A0A, /* DRAM size information */ - .mc_emem_adr_cfg = 0x00000001, - .mc_emem_adr_cfg_dev0 = 0x00070302, - .mc_emem_adr_cfg_dev1 = 0x00070302, + .mc_emem_adr_cfg = 0x00000001, // 2 populated DRAM Devices. + .mc_emem_adr_cfg_dev0 = 0x00070302, // Density 512MB. + .mc_emem_adr_cfg_dev1 = 0x00070302, // Density 512MB. .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, .mc_emem_adr_cfg_bank_mask1 = 0x39722800, @@ -516,7 +501,7 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { * Specifies the value for MC_EMEM_CFG which holds the external memory * size (in KBytes) */ - .mc_emem_cfg = 0x00001000, + .mc_emem_cfg = 0x00001000, // 4GB total density. /* MC arbitration configuration */ .mc_emem_arb_cfg = 0x08000001, @@ -659,7 +644,7 @@ static const sdram_params_t _dram_cfg_0_samsung_4gb = { .mc_mts_carveout_reg_ctrl = 0x00000000 }; -static const sdram_vendor_patch_t sdram_cfg_vendor_patches[] = { +static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = { // Hynix timing config. { 0x0000000D, 67, DRAM_ID(1) | DRAM_ID(5) }, // emc_r2w. { 0x00000001, 91, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_extra. diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl new file mode 100644 index 0000000..983c93a --- /dev/null +++ b/bdk/mem/sdram_config_t210b01.inl @@ -0,0 +1,1002 @@ +/* + * Copyright (c) 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 . + */ + +#define DRAM_CFG_T210B01_SIZE 2104 + +#define DRAM_ID2(x) BIT((x) - 7) + +static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { + /* Specifies the type of memory device */ + .memory_type = MEMORY_TYPE_LPDDR4, + + /* MC/EMC clock source configuration */ + .pllm_input_divider = 0x00000001, // M div. + .pllm_feedback_divider = 0x00000022, // N div. + .pllm_stable_time = 0x0000012C, + .pllm_setup_control = 0x00000000, + .pllm_post_divider = 0x00000000, // P div. + .pllm_kcp = 0x00000000, + .pllm_kvco = 0x00000000, + + /* Spare BCT params */ + .emc_bct_spare0 = 0x00000000, + .emc_bct_spare1 = 0x00000000, + .emc_bct_spare2 = 0x00000000, + .emc_bct_spare3 = 0x00000000, + .emc_bct_spare4 = 0x00000000, + .emc_bct_spare5 = 0x00000000, + .emc_bct_spare6 = 0x00000000, + .emc_bct_spare7 = 0x00000000, + .emc_bct_spare8 = 0x00000000, + .emc_bct_spare9 = 0x00000000, + .emc_bct_spare10 = 0x00000000, + .emc_bct_spare11 = 0x00000000, + .emc_bct_spare12 = 0x00000000, + .emc_bct_spare13 = 0x00000000, + + .emc_bct_spare_secure0 = 0x00000000, + .emc_bct_spare_secure1 = 0x00000000, + .emc_bct_spare_secure2 = 0x00000000, + .emc_bct_spare_secure3 = 0x00000000, + .emc_bct_spare_secure4 = 0x00000000, + .emc_bct_spare_secure5 = 0x00000000, + .emc_bct_spare_secure6 = 0x00000000, + .emc_bct_spare_secure7 = 0x00000000, + .emc_bct_spare_secure8 = 0x00000000, + .emc_bct_spare_secure9 = 0x00000000, + .emc_bct_spare_secure10 = 0x00000000, + .emc_bct_spare_secure11 = 0x00000000, + .emc_bct_spare_secure12 = 0x00000000, + .emc_bct_spare_secure13 = 0x00000000, + .emc_bct_spare_secure14 = 0x00000000, + .emc_bct_spare_secure15 = 0x00000000, + .emc_bct_spare_secure16 = 0x00000000, + .emc_bct_spare_secure17 = 0x00000000, + .emc_bct_spare_secure18 = 0x00000000, + .emc_bct_spare_secure19 = 0x00000000, + .emc_bct_spare_secure20 = 0x00000000, + .emc_bct_spare_secure21 = 0x00000000, + .emc_bct_spare_secure22 = 0x00000000, + .emc_bct_spare_secure23 = 0x00000000, + + /* EMC clock configuration */ + .emc_clock_source = 0x40188002, + .emc_clock_source_dll = 0x40000000, + + .clk_rst_pllm_misc20_override = 0x00000000, + .clk_rst_pllm_misc20_override_enable = 0x00000000, + + .clear_clock2_mc1 = 0x00000000, + + /* Auto-calibration of EMC pads */ + .emc_auto_cal_interval = 0x001FFFFF, + + .emc_auto_cal_config = 0xA01A51D8, + .emc_auto_cal_config2 = 0x00000000, + .emc_auto_cal_config3 = 0x00880000, + + .emc_auto_cal_config4 = 0x00880000, + .emc_auto_cal_config5 = 0x00001220, + .emc_auto_cal_config6 = 0x00880000, + .emc_auto_cal_config7 = 0x00880000, + .emc_auto_cal_config8 = 0x00880000, + .emc_auto_cal_config9 = 0x00000000, + + .emc_auto_cal_vref_sel0 = 0xB3C5BCBC, + .emc_auto_cal_vref_sel1 = 0x00009E3C, + + .emc_auto_cal_channel = 0xC1E00302, + + .emc_pmacro_auto_cal_cfg0 = 0x04040404, + .emc_pmacro_auto_cal_cfg1 = 0x04040404, + .emc_pmacro_auto_cal_cfg2 = 0x04040404, + + .emc_pmacro_rx_term = 0x3F3F3F3F, + .emc_pmacro_dq_tx_drive = 0x3F3F3F3F, + .emc_pmacro_ca_tx_drive = 0x3F3F3F3F, + .emc_pmacro_cmd_tx_drive = 0x00001220, + .emc_pmacro_auto_cal_common = 0x00000804, + .emc_pmacro_zcrtl = 0x505050, + + /* Specifies the time for the calibration to stabilize (in microseconds) */ + .emc_auto_cal_wait = 0x000001A1, + + .emc_xm2_comp_pad_ctrl = 0x00000030, + .emc_xm2_comp_pad_ctrl2 = 0x16001000, + .emc_xm2_comp_pad_ctrl3 = 0x00901000, + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + .emc_adr_cfg = 0x00000000, // 1 populated DRAM Device. + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + .emc_pin_program_wait = 0x00000002, + /* Specifies the extra delay before/after pin RESET/CKE command */ + .emc_pin_extra_wait = 0x00000000, + + .emc_pin_gpio_enable = 0x00000003, + .emc_pin_gpio = 0x00000003, + + /* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */ + .emc_timing_control_wait = 0x0000001E, + + /* Timing parameters required for the SDRAM */ + .emc_rc = 0x0000000D, + .emc_rfc = 0x0000003A, + .emc_rfc_pb = 0x0000001D, + .emc_ref_ctrl2 = 0x00000000, + .emc_rfc_slr = 0x00000000, + .emc_ras = 0x00000009, + .emc_rp = 0x00000004, + .emc_r2r = 0x00000000, + .emc_w2w = 0x00000000, + .emc_r2w = 0x0000000B, + .emc_w2r = 0x0000000D, + .emc_r2p = 0x00000008, + .emc_w2p = 0x0000000B, + .emc_tppd = 0x00000004, + .emc_trtm = 0x00000017, + .emc_twtm = 0x00000015, + .emc_tratm = 0x00000017, + .emc_twatm = 0x0000001B, + .emc_tr2ref = 0x00000000, + .emc_ccdmw = 0x00000020, + .emc_rd_rcd = 0x00000006, + .emc_wr_rcd = 0x00000006, + .emc_rrd = 0x00000006, + .emc_rext = 0x00000003, + .emc_wext = 0x00000000, + .emc_wdv = 0x00000004, + .emc_wdv_chk = 0x00000006, + .emc_wsv = 0x00000002, + .emc_wev = 0x00000000, + .emc_wdv_mask = 0x00000004, + .emc_ws_duration = 0x00000008, + .emc_we_duration = 0x0000000E, + .emc_quse = 0x00000005, + .emc_quse_width = 0x00000006, + .emc_ibdly = 0x00000000, + .emc_obdly = 0x00000000, + .emc_einput = 0x00000002, + .emc_einput_duration = 0x0000000D, + .emc_puterm_extra = 0x00000001, + .emc_puterm_width = 0x80000000, + .emc_qrst = 0x00010000, + .emc_qsafe = 0x00000012, + .emc_rdv = 0x00000018, + .emc_rdv_mask = 0x0000001A, + .emc_rdv_early = 0x00000016, + .emc_rdv_early_mask = 0x00000018, + .emc_qpop = 0x0000000A, + .emc_refresh = 0x00000304, + .emc_burst_refresh_num = 0x00000000, + .emc_prerefresh_req_cnt = 0x000000C1, + .emc_pdex2wr = 0x00000008, + .emc_pdex2rd = 0x00000008, + .emc_pchg2pden = 0x00000003, + .emc_act2pden = 0x0000000A, + .emc_ar2pden = 0x00000003, + .emc_rw2pden = 0x00000014, + .emc_cke2pden = 0x00000005, + .emc_pdex2che = 0x00000002, + .emc_pdex2mrr = 0x0000000D, + .emc_txsr = 0x0000003B, + .emc_txsr_dll = 0x0000003B, + .emc_tcke = 0x00000005, + .emc_tckesr = 0x00000005, + .emc_tpd = 0x00000004, + .emc_tfaw = 0x00000009, + .emc_trpab = 0x00000005, + .emc_tclkstable = 0x00000004, + .emc_tclkstop = 0x00000009, + .emc_trefbw = 0x0000031C, + + /* FBIO configuration values */ + .emc_fbio_cfg5 = 0x9160A00D, + .emc_fbio_cfg7 = 0x00003A3F, + .emc_fbio_cfg8 = 0x0CF30000, + + /* Command mapping for CMD brick 0 */ + .emc_cmd_mapping_cmd0_0 = 0x061B0504, + .emc_cmd_mapping_cmd0_1 = 0x1C070302, + .emc_cmd_mapping_cmd0_2 = 0x05252523, + .emc_cmd_mapping_cmd1_0 = 0x0A091D08, + .emc_cmd_mapping_cmd1_1 = 0x0D1E0B24, + .emc_cmd_mapping_cmd1_2 = 0x0326260C, + .emc_cmd_mapping_cmd2_0 = 0x231C1B02, + .emc_cmd_mapping_cmd2_1 = 0x05070403, + .emc_cmd_mapping_cmd2_2 = 0x02252506, + .emc_cmd_mapping_cmd3_0 = 0x0D1D0B0A, + .emc_cmd_mapping_cmd3_1 = 0x1E090C08, + .emc_cmd_mapping_cmd3_2 = 0x08262624, + .emc_cmd_mapping_byte = 0x9A070624, + + .emc_fbio_spare = 0x00000012, + .emc_cfg_rsv = 0xFF00FF00, + + /* MRS command values */ + .emc_mrs = 0x00000000, + .emc_emrs = 0x00000000, + .emc_emrs2 = 0x00000000, + .emc_emrs3 = 0x00000000, + .emc_mrw1 = 0x88010004, + .emc_mrw2 = 0x88020000, + .emc_mrw3 = 0x880D0000, + .emc_mrw4 = 0xC0000000, + .emc_mrw6 = 0x88033131, + .emc_mrw8 = 0x880B0000, + .emc_mrw9 = 0x8C0E5D5D, + .emc_mrw10 = 0x880C5D5D, + .emc_mrw12 = 0x8C0D0808, + .emc_mrw13 = 0x8C0D0000, + .emc_mrw14 = 0x88161616, + .emc_mrw_extra = 0x88010004, + .emc_warm_boot_mrw_extra = 0x08110000, + .emc_warm_boot_extramode_reg_write_enable = 0x00000001, + .emc_extramode_reg_write_enable = 0x00000000, + .emc_mrw_reset_command = 0x00000000, + .emc_mrw_reset_ninit_wait = 0x00000000, + .emc_mrs_wait_cnt = 0x00CC0010, + .emc_mrs_wait_cnt2 = 0x0033000A, + + /* EMC miscellaneous configurations */ + .emc_cfg = 0xF3200000, + .emc_cfg2 = 0x00110825, + .emc_cfg_pipe = 0x0FFF0000, + .emc_cfg_pipe_clk = 0x00000000, + .emc_fdpd_ctrl_cmd_no_ramp = 0x00000001, + .emc_cfg_update = 0x70000301, + .emc_dbg = 0x01000C00, + .emc_dbg_write_mux = 0x00000001, + .emc_cmd_q = 0x10004408, + .emc_mc2emc_q = 0x06000404, + .emc_dyn_self_ref_control = 0x00000713, + .ahb_arbitration_xbar_ctrl_meminit_done = 0x00000001, + .emc_cfg_dig_dll = 0x002C00A0, + .emc_cfg_dig_dll_1 = 0x000F3701, + .emc_cfg_dig_dll_period = 0x00008000, + .emc_dev_select = 0x00000002, // Dev0 only. + .emc_sel_dpd_ctrl = 0x0004000C, + + /* Pads trimmer delays */ + .emc_fdpd_ctrl_dq = 0x8020221F, + .emc_fdpd_ctrl_cmd = 0x0220F40F, + .emc_pmacro_ib_vref_dq_0 = 0x29292929, + .emc_pmacro_ib_vref_dq_1 = 0x29292929, + .emc_pmacro_ib_vref_dqs_0 = 0x29292929, + .emc_pmacro_ib_vref_dqs_1 = 0x29292929, + .emc_pmacro_ib_rxrt = 0x00000078, + .emc_cfg_pipe1 = 0x0FFF0000, + .emc_cfg_pipe2 = 0x00000000, + + .emc_pmacro_quse_ddll_rank0_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_5 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_5 = 0x00000000, + + .emc_pmacro_ob_ddll_long_dq_rank0_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_4 = 0x000D0016, + .emc_pmacro_ob_ddll_long_dq_rank0_5 = 0x0017000B, + .emc_pmacro_ob_ddll_long_dq_rank1_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_4 = 0x000D0016, + .emc_pmacro_ob_ddll_long_dq_rank1_5 = 0x0017000B, + + .emc_pmacro_ob_ddll_long_dqs_rank0_0 = 0x00450043, + .emc_pmacro_ob_ddll_long_dqs_rank0_1 = 0x00430045, + .emc_pmacro_ob_ddll_long_dqs_rank0_2 = 0x00470046, + .emc_pmacro_ob_ddll_long_dqs_rank0_3 = 0x00460041, + .emc_pmacro_ob_ddll_long_dqs_rank0_4 = 0x0003000C, + .emc_pmacro_ob_ddll_long_dqs_rank0_5 = 0x000D0000, + .emc_pmacro_ob_ddll_long_dqs_rank1_0 = 0x00450043, + .emc_pmacro_ob_ddll_long_dqs_rank1_1 = 0x00430045, + .emc_pmacro_ob_ddll_long_dqs_rank1_2 = 0x00470046, + .emc_pmacro_ob_ddll_long_dqs_rank1_3 = 0x00460041, + .emc_pmacro_ob_ddll_long_dqs_rank1_4 = 0x0003000C, + .emc_pmacro_ob_ddll_long_dqs_rank1_5 = 0x000D0000, + + .emc_pmacro_ib_ddll_long_dqs_rank0_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_3 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_3 = 0x00280028, + + .emc_pmacro_ddll_long_cmd_0 = 0x00160016, + .emc_pmacro_ddll_long_cmd_1 = 0x000D000D, + .emc_pmacro_ddll_long_cmd_2 = 0x000B000B, + .emc_pmacro_ddll_long_cmd_3 = 0x00170017, + .emc_pmacro_ddll_long_cmd_4 = 0x00000016, + .emc_pmacro_ddll_short_cmd_0 = 0x00000000, + .emc_pmacro_ddll_short_cmd_1 = 0x00000000, + .emc_pmacro_ddll_short_cmd_2 = 0x00000000, + + .emc_pmacro_ddll_periodic_offset = 0x00000000, + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + .warm_boot_wait = 0x00000001, + + .emc_odt_write = 0x00000000, + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + .emc_zcal_interval = 0x00064000, + .emc_zcal_wait_cnt = 0x000900CC, + .emc_zcal_mrw_cmd = 0x8051004F, + + /* DRAM initialization sequence flow control */ + .emc_mrs_reset_dll = 0x00000000, + .emc_zcal_init_dev0 = 0x80000001, + .emc_zcal_init_dev1 = 0x00000000, + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + .emc_zcal_init_wait = 0x00000001, + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + .emc_zcal_warm_cold_boot_enables = 0x00000003, + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + .emc_mrw_lpddr2zcal_warm_boot = 0x040A00AB, + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + .emc_zqcal_ddr3_warm_boot = 0x00000011, + .emc_zqcal_lpddr4_warm_boot = 0x00000001, + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + .emc_zcal_warm_boot_wait = 0x00000001, + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + .emc_mrs_warm_boot_enable = 0x00000001, + .emc_mrs_reset_dll_wait = 0x00000000, + .emc_mrs_extra = 0x00000000, + .emc_warm_boot_mrs_extra = 0x00000000, + .emc_emrs_ddr2_dll_enable = 0x00000000, + .emc_mrs_ddr2_dll_reset = 0x00000000, + .emc_emrs_ddr2_ocd_calib = 0x00000000, + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + .emc_ddr2_wait = 0x00000000, + .emc_clken_override = 0x00000000, + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + .emc_extra_refresh_num = 0x00000002, + .emc_clken_override_allwarm_boot = 0x00000000, + .mc_clken_override_allwarm_boot = 0x00000000, + /* Specifies digital dll period, choosing between 4 to 64 ms */ + .emc_cfg_dig_dll_period_warm_boot = 0x00000003, + + /* Pad controls */ + .pmc_vddp_sel = 0x00000001, + .pmc_vddp_sel_wait = 0x00000002, + .pmc_ddr_cfg = 0x04220100, + .pmc_io_dpd3_req = 0x4FAF9FFF, + .pmc_io_dpd3_req_wait = 0x00000001, + .pmc_io_dpd4_req_wait = 0x00000002, + .pmc_reg_short = 0x00000000, + .pmc_no_io_power = 0x00000000, + .pmc_ddr_ctrl_wait = 0x00000000, + .pmc_ddr_ctrl = 0x0037FF9F, + .emc_acpd_control = 0x00000000, + + .emc_swizzle_rank0_byte0 = 0x76543201, + .emc_swizzle_rank0_byte1 = 0x65324710, + .emc_swizzle_rank0_byte2 = 0x25763410, + .emc_swizzle_rank0_byte3 = 0x25673401, + .emc_swizzle_rank1_byte0 = 0x32647501, + .emc_swizzle_rank1_byte1 = 0x34567201, + .emc_swizzle_rank1_byte2 = 0x56742310, + .emc_swizzle_rank1_byte3 = 0x67324501, + + .emc_txdsrvttgen = 0x00000000, + + .emc_data_brlshft0 = 0x00249249, + .emc_data_brlshft1 = 0x00249249, + + .emc_dqs_brlshft0 = 0x00000000, + .emc_dqs_brlshft1 = 0x00000000, + + .emc_cmd_brlshft0 = 0x00000000, + .emc_cmd_brlshft1 = 0x00000000, + .emc_cmd_brlshft2 = 0x00000012, + .emc_cmd_brlshft3 = 0x00000012, + + .emc_quse_brlshft0 = 0x00000000, + .emc_quse_brlshft1 = 0x00000000, + .emc_quse_brlshft2 = 0x00000000, + .emc_quse_brlshft3 = 0x00000000, + + .emc_dll_cfg0 = 0x1F134120, + .emc_dll_cfg1 = 0x00010014, + + .emc_pmc_scratch1 = 0x4FAF9FFF, + .emc_pmc_scratch2 = 0x7FFFFFFF, + .emc_pmc_scratch3 = 0x4036D71F, + + .emc_pmacro_pad_cfg_ctrl = 0x00000000, + .emc_pmacro_vttgen_ctrl0 = 0x00090000, + .emc_pmacro_vttgen_ctrl1 = 0x00103400, + .emc_pmacro_vttgen_ctrl2 = 0x00000000, + .emc_pmacro_dsr_vttgen_ctrl0 = 0x00000009, + .emc_pmacro_brick_ctrl_rfu1 = 0x00000000, + .emc_pmacro_cmd_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_brick_ctrl_rfu2 = 0x00000000, + .emc_pmacro_data_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_bg_bias_ctrl0 = 0x00000000, + .emc_pmacro_data_pad_rx_ctrl = 0x05050003, + .emc_pmacro_cmd_pad_rx_ctrl = 0x05000000, + .emc_pmacro_data_rx_term_mode = 0x00000210, + .emc_pmacro_cmd_rx_term_mode = 0x00002000, + .emc_pmacro_data_pad_tx_ctrl = 0x00000421, + .emc_pmacro_cmd_pad_tx_ctrl = 0x00000000, + + .emc_cfg3 = 0x00000040, + + .emc_pmacro_tx_pwrd0 = 0x10000000, + .emc_pmacro_tx_pwrd1 = 0x00000000, + .emc_pmacro_tx_pwrd2 = 0x00000000, + .emc_pmacro_tx_pwrd3 = 0x00000000, + .emc_pmacro_tx_pwrd4 = 0x00400080, + .emc_pmacro_tx_pwrd5 = 0x00801004, + + .emc_config_sample_delay = 0x00000020, + + .emc_pmacro_brick_mapping0 = 0x28091081, + .emc_pmacro_brick_mapping1 = 0x44A53293, + .emc_pmacro_brick_mapping2 = 0x76678A5B, + + .emc_pmacro_tx_sel_clk_src0 = 0x00000000, + .emc_pmacro_tx_sel_clk_src1 = 0x00000000, + .emc_pmacro_tx_sel_clk_src2 = 0x00000000, + .emc_pmacro_tx_sel_clk_src3 = 0x00000000, + .emc_pmacro_tx_sel_clk_src4 = 0x00000000, + .emc_pmacro_tx_sel_clk_src5 = 0x00000000, + + .emc_pmacro_perbit_fgcg_ctrl0 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl1 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl2 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl3 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl4 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl5 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl0 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl1 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl2 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl3 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl4 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl5 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl0 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl1 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl2 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl3 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl4 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl5 = 0x00000000, + + .emc_pmacro_data_pi_ctrl = 0x00001010, + .emc_pmacro_cmd_pi_ctrl = 0x00001010, + + .emc_pmacro_ddll_bypass = 0xEF00EF00, + + .emc_pmacro_ddll_pwrd0 = 0x00000000, + .emc_pmacro_ddll_pwrd1 = 0x00000000, + .emc_pmacro_ddll_pwrd2 = 0x1C1C1C1C, + + .emc_pmacro_cmd_ctrl0 = 0x00000000, + .emc_pmacro_cmd_ctrl1 = 0x00000000, + .emc_pmacro_cmd_ctrl2 = 0x00000000, + + /* DRAM size information */ + .mc_emem_adr_cfg = 0x00000000, // 1 populated DRAM Device. + .mc_emem_adr_cfg_dev0 = 0x00080302, // Density 1024MB. + .mc_emem_adr_cfg_dev1 = 0x00080302, // Density 1024MB. + .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, + .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, + .mc_emem_adr_cfg_bank_mask1 = 0x39722800, + .mc_emem_adr_cfg_bank_mask2 = 0x4B9C1000, + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + .mc_emem_cfg = 0x00001000, // 4GB total density. + + /* MC arbitration configuration */ + .mc_emem_arb_cfg = 0x08000001, + .mc_emem_arb_outstanding_req = 0x8000004C, + .emc_emem_arb_refpb_hp_ctrl = 0x000A1020, + .emc_emem_arb_refpb_bank_ctrl = 0x80001028, + + .mc_emem_arb_timing_rcd = 0x00000001, + .mc_emem_arb_timing_rp = 0x00000000, + .mc_emem_arb_timing_rc = 0x00000003, + .mc_emem_arb_timing_ras = 0x00000001, + .mc_emem_arb_timing_faw = 0x00000002, + .mc_emem_arb_timing_rrd = 0x00000001, + .mc_emem_arb_timing_rap2pre = 0x00000002, + .mc_emem_arb_timing_wap2pre = 0x00000005, + .mc_emem_arb_timing_r2r = 0x00000001, + .mc_emem_arb_timing_w2w = 0x00000001, + .mc_emem_arb_timing_r2w = 0x00000004, + .mc_emem_arb_timing_w2r = 0x00000005, + .mc_emem_arb_timing_rfcpb = 0x00000007, + + .mc_emem_arb_da_turns = 0x02020000, + .mc_emem_arb_da_covers = 0x00030201, + .mc_emem_arb_misc0 = 0x72A30504, + .mc_emem_arb_misc1 = 0x70000F0F, + .mc_emem_arb_misc2 = 0x00000000, + + .mc_emem_arb_ring1_throttle = 0x001F0000, + .mc_emem_arb_override = 0x10000000, + .mc_emem_arb_override1 = 0x00000000, + .mc_emem_arb_rsv = 0xFF00FF00, + + .mc_da_cfg0 = 0x00000001, + .mc_emem_arb_timing_ccdmw = 0x00000008, + + .mc_clken_override = 0x00008000, + + .mc_stat_control = 0x00000000, + .mc_video_protect_bom = 0xFFF00000, + .mc_video_protect_bom_adr_hi = 0x00000000, + .mc_video_protect_size_mb = 0x00000000, + .mc_video_protect_vpr_override = 0xE4BAC343, + .mc_video_protect_vpr_override1 = 0x06001ED3, // Add SE2, SE2B. + .mc_video_protect_gpu_override0 = 0x00000000, + .mc_video_protect_gpu_override1 = 0x00000000, + .mc_sec_carveout_bom = 0xFFF00000, + .mc_sec_carveout_adr_hi = 0x00000000, + .mc_sec_carveout_size_mb = 0x00000000, + .mc_video_protect_write_access = 0x00000000, + .mc_sec_carveout_protect_write_access = 0x00000000, + + .mc_generalized_carveout1_bom = 0x00000000, + .mc_generalized_carveout1_bom_hi = 0x00000000, + .mc_generalized_carveout1_size_128kb = 0x00000008, + .mc_generalized_carveout1_access0 = 0x00000000, + .mc_generalized_carveout1_access1 = 0x00000000, + .mc_generalized_carveout1_access2 = 0x00300000, + .mc_generalized_carveout1_access3 = 0x03000000, + .mc_generalized_carveout1_access4 = 0x00000000, + .mc_generalized_carveout1_force_internal_access0 = 0x00000000, + .mc_generalized_carveout1_force_internal_access1 = 0x00000000, + .mc_generalized_carveout1_force_internal_access2 = 0x00000000, + .mc_generalized_carveout1_force_internal_access3 = 0x00000000, + .mc_generalized_carveout1_force_internal_access4 = 0x00000000, + .mc_generalized_carveout1_cfg0 = 0x04000C76, + + .mc_generalized_carveout2_bom = 0x00000000, + .mc_generalized_carveout2_bom_hi = 0x00000000, + .mc_generalized_carveout2_size_128kb = 0x00000002, + .mc_generalized_carveout2_access0 = 0x00000000, + .mc_generalized_carveout2_access1 = 0x00000000, + .mc_generalized_carveout2_access2 = 0x03000000, + .mc_generalized_carveout2_access3 = 0x00000000, + .mc_generalized_carveout2_access4 = 0x00000300, + .mc_generalized_carveout2_force_internal_access0 = 0x00000000, + .mc_generalized_carveout2_force_internal_access1 = 0x00000000, + .mc_generalized_carveout2_force_internal_access2 = 0x00000000, + .mc_generalized_carveout2_force_internal_access3 = 0x00000000, + .mc_generalized_carveout2_force_internal_access4 = 0x00000000, + .mc_generalized_carveout2_cfg0 = 0x0440167E, + + .mc_generalized_carveout3_bom = 0x00000000, + .mc_generalized_carveout3_bom_hi = 0x00000000, + .mc_generalized_carveout3_size_128kb = 0x00000000, + .mc_generalized_carveout3_access0 = 0x00000000, + .mc_generalized_carveout3_access1 = 0x00000000, + .mc_generalized_carveout3_access2 = 0x03000000, + .mc_generalized_carveout3_access3 = 0x00000000, + .mc_generalized_carveout3_access4 = 0x00000300, + .mc_generalized_carveout3_force_internal_access0 = 0x00000000, + .mc_generalized_carveout3_force_internal_access1 = 0x00000000, + .mc_generalized_carveout3_force_internal_access2 = 0x00000000, + .mc_generalized_carveout3_force_internal_access3 = 0x00000000, + .mc_generalized_carveout3_force_internal_access4 = 0x00000000, + .mc_generalized_carveout3_cfg0 = 0x04401E7E, + + .mc_generalized_carveout4_bom = 0x00000000, + .mc_generalized_carveout4_bom_hi = 0x00000000, + .mc_generalized_carveout4_size_128kb = 0x00000008, + .mc_generalized_carveout4_access0 = 0x00000000, + .mc_generalized_carveout4_access1 = 0x00000000, + .mc_generalized_carveout4_access2 = 0x00300000, + .mc_generalized_carveout4_access3 = 0x00000000, + .mc_generalized_carveout4_access4 = 0x000000C0, + .mc_generalized_carveout4_force_internal_access0 = 0x00000000, + .mc_generalized_carveout4_force_internal_access1 = 0x00000000, + .mc_generalized_carveout4_force_internal_access2 = 0x00000000, + .mc_generalized_carveout4_force_internal_access3 = 0x00000000, + .mc_generalized_carveout4_force_internal_access4 = 0x00000000, + .mc_generalized_carveout4_cfg0 = 0x04002446, + + .mc_generalized_carveout5_bom = 0x00000000, + .mc_generalized_carveout5_bom_hi = 0x00000000, + .mc_generalized_carveout5_size_128kb = 0x00000008, + .mc_generalized_carveout5_access0 = 0x00000000, + .mc_generalized_carveout5_access1 = 0x00000000, + .mc_generalized_carveout5_access2 = 0x00300000, + .mc_generalized_carveout5_access3 = 0x00000000, + .mc_generalized_carveout5_access4 = 0x00000000, + .mc_generalized_carveout5_force_internal_access0 = 0x00000000, + .mc_generalized_carveout5_force_internal_access1 = 0x00000000, + .mc_generalized_carveout5_force_internal_access2 = 0x00000000, + .mc_generalized_carveout5_force_internal_access3 = 0x00000000, + .mc_generalized_carveout5_force_internal_access4 = 0x00000000, + .mc_generalized_carveout5_cfg0 = 0x04002C46, + + /* Specifies enable for CA training */ + .emc_ca_training_enable = 0x00000000, + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + .swizzle_rank_byte_encode = 0x000000EC, + + /* Specifies enable and offset for patched boot rom write */ + .boot_rom_patch_control = 0x00000000, + /* Specifies data for patched boot rom write */ + .boot_rom_patch_data = 0x00000000, + + .mc_mts_carveout_bom = 0xFFF00000, + .mc_mts_carveout_adr_hi = 0x00000000, + .mc_mts_carveout_size_mb = 0x00000000, + .mc_mts_carveout_reg_ctrl = 0x00000000, + + /* Specifies the untranslated memory access control */ + .mc_untranslated_region_check = 0x00000000, + + /* Just a place holder for special usage when there is no BCT for certain registers */ + .bct_na = 0x00000000, +}; + +//!TODO Find out what mc_video_protect_gpu_override0 and mc_video_protect_gpu_override1 new bits are. + +static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { + + // Samsung LPDDR4X 4GB X1X2 for prototype Iowa. + { 0x000E0022, 0x3AC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x001B0010, 0x3B0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x000E0022, 0x3C4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x001B0010, 0x3C8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x00490043, 0x3CC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00420045, 0x3D0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00490047, 0x3D4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x00460047, 0x3D8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x00000016, 0x3DC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00100000, 0x3E0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. + { 0x00490043, 0x3E4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00420045, 0x3E8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00490047, 0x3EC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x00460047, 0x3F0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x00000016, 0x3F4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00100000, 0x3F8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. + { 0x00220022, 0x41C / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_0. + { 0x000E000E, 0x420 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_1. + { 0x00100010, 0x424 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_2. + { 0x001B001B, 0x428 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000022, 0x42C / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_4. + + // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ for SDEV Iowa and Hoag. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000006, 0x1CC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse. + { 0x00000005, 0x1D0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_einput_duration. + { 0x08010004, 0x2B8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_dev_select. Both devices. + { 0x35353535, 0x350 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_vref_dq_0. + { 0x35353535, 0x354 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_vref_dq_1. + { 0x00100010, 0x3FC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. + { 0x00100010, 0x400 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. + { 0x00100010, 0x404 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. + { 0x00100010, 0x408 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. + { 0x00100010, 0x40C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. + { 0x00100010, 0x410 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. + { 0x00100010, 0x414 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. + { 0x00100010, 0x418 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. + { 0x0051004F, 0x450 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00002000, 0x64C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_cfg. 8GB total density. + { 0x00000002, 0x680 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_video_protect_gpu_override1. + + // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT for Iowa and Hoag. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_auto_cal_vref_sel0. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_dyn_self_ref_control. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 4GB Die-Y for Iowa. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(16) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(16) }, // emc_auto_cal_vref_sel0. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(16) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(16) }, // emc_dyn_self_ref_control. + { 0x32323232, 0x350 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_vref_dq_0. + { 0x32323232, 0x354 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_vref_dq_1. + { 0x000F0018, 0x3AC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00780078, 0x3FC / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. + { 0x00780078, 0x400 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. + { 0x00780078, 0x404 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. + { 0x00780078, 0x408 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. + { 0x00780078, 0x40C / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. + { 0x00780078, 0x410 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. + { 0x00780078, 0x414 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. + { 0x00780078, 0x418 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. + { 0x00180018, 0x41C / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_4. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 4GB 10nm-class (1y) Die-X for Iowa, Hoag and SDS. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_quse. + { 0x00000005, 0x1D0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_einput_duration. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_dyn_self_ref_control. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 8GB 10nm-class (1y) Die-X for SDEV Iowa and SDS. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000006, 0x1CC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse. + { 0x00000005, 0x1D0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_tfaw. + { 0x08010004, 0x2B8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_dev_select. Both devices. + { 0x0051004F, 0x450 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00002000, 0x64C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_cfg. 8GB total density. + { 0x00000001, 0x670 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_faw. + { 0x00000002, 0x680 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 4GB 10nm-class (1y) Die-Y for Iowa. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(20) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(20) }, // emc_auto_cal_vref_sel0. + { 0x00000008, 0x24C / 4, DRAM_ID2(20) }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(20) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(20) }, // emc_dyn_self_ref_control. + { 0x000F0018, 0x3AC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00180018, 0x41C / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_4. + { 0x00000001, 0x670 / 4, DRAM_ID2(20) }, // mc_emem_arb_timing_faw. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(20) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(20) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 8GB 10nm-class (1y) Die-Y for SDEV Iowa. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(21) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(21) }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, DRAM_ID2(21) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000008, 0x24C / 4, DRAM_ID2(21) }, // emc_tfaw. + { 0x08010004, 0x2B8 / 4, DRAM_ID2(21) }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, DRAM_ID2(21) }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, DRAM_ID2(21) }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, DRAM_ID2(21) }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, DRAM_ID2(21) }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(21) }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(21) }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(21) }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(21) }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, DRAM_ID2(21) }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, DRAM_ID2(21) }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, DRAM_ID2(21) }, // emc_dev_select. Both devices. + { 0x32323232, 0x350 / 4, DRAM_ID2(21) }, // emc_pmacro_ib_vref_dq_0. + { 0x32323232, 0x354 / 4, DRAM_ID2(21) }, // emc_pmacro_ib_vref_dq_1. + { 0x000F0018, 0x3AC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00180018, 0x41C / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_4. + { 0x0051004F, 0x450 / 4, DRAM_ID2(21) }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, DRAM_ID2(21) }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, DRAM_ID2(21) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00002000, 0x64C / 4, DRAM_ID2(21) }, // mc_emem_cfg. 8GB total density. + { 0x00000001, 0x670 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_faw. + { 0x00000002, 0x680 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, DRAM_ID2(21) }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override1. + + // Samsung LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown SDS. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(22) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(22) }, // emc_auto_cal_vref_sel0. + { 0x00000008, 0x24C / 4, DRAM_ID2(22) }, // emc_tfaw. + { 0x1C041B06, 0x26C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_0. + { 0x02050307, 0x270 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_1. + { 0x03252500, 0x274 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_2. + { 0x081D1E00, 0x278 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_0. + { 0x090C0A0D, 0x27C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_1. + { 0x0526260B, 0x280 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_2. + { 0x05030402, 0x284 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_0. + { 0x1B1C0600, 0x288 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_1. + { 0x07252507, 0x28C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_2. + { 0x0C1D0B0A, 0x290 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_0. + { 0x0800090D, 0x294 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_1. + { 0x0926261E, 0x298 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_2. + { 0x2A080624, 0x29C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_byte. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(22) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(22) }, // emc_dyn_self_ref_control. + { 0x00140010, 0x3AC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x0013000B, 0x3B0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x00140010, 0x3C4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x0013000B, 0x3C8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x00450047, 0x3CC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x004D004F, 0x3D0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00460046, 0x3D4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x00480048, 0x3D8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x000C0008, 0x3DC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x000B000C, 0x3E0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. + { 0x00450047, 0x3E4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x004D004F, 0x3E8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00460046, 0x3EC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x00480048, 0x3F0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x000C0008, 0x3F4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x000B000C, 0x3F8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. + { 0x00100010, 0x41C / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_0. + { 0x00140014, 0x420 / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_1. + { 0x00130013, 0x428 / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000010, 0x42C / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_4. + { 0x40280100, 0x4B4 / 4, DRAM_ID2(22) }, // pmc_ddr_cfg. + { 0x4F9F9FFF, 0x4B8 / 4, DRAM_ID2(22) }, // pmc_io_dpd3_req. + { 0x64032157, 0x4D8 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte0. + { 0x51320467, 0x4DC / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte1. + { 0x04735621, 0x4E0 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte2. + { 0x47356012, 0x4E4 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte3. + { 0x12045673, 0x4E8 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte0. + { 0x43657210, 0x4EC / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte1. + { 0x65402137, 0x4F0 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte2. + { 0x57302164, 0x4F4 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte3. + { 0x4F9F9FFF, 0x534 / 4, DRAM_ID2(22) }, // emc_pmc_scratch1. + { 0x4033CF1F, 0x53C / 4, DRAM_ID2(22) }, // emc_pmc_scratch3. + { 0x10000000, 0x590 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd3. + { 0x00030108, 0x594 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd4. + { 0x01400050, 0x598 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd5. + { 0x29081081, 0x5A0 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping0. + { 0x54A59332, 0x5A4 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping1. + { 0x87766B4A, 0x5A8 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping2. + { 0x00000001, 0x670 / 4, DRAM_ID2(22) }, // mc_emem_arb_timing_faw. + { 0xE4FACB43, 0x6D4 / 4, DRAM_ID2(22) }, // mc_video_protect_vpr_override. + TSEC, NVENC. + { 0x0600FED3, 0x6D8 / 4, DRAM_ID2(22) }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(22) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(22) }, // mc_video_protect_gpu_override1. + { 0x0000009C, 0x814 / 4, DRAM_ID2(22) }, // swizzle_rank_byte_encode. + + // Micron LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Iowa/Hoag/SDS. + { 0x05500000, 0x0D4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_quse. + { 0x00000005, 0x1D0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_mrw14. + { 0x80000713, 0x32C / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_dyn_self_ref_control. + { 0x00000001, 0x670 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_emem_arb_timing_faw. + { 0x2A800000, 0x6DC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_video_protect_gpu_override1. +}; diff --git a/bdk/mem/sdram_lp0.c b/bdk/mem/sdram_lp0.c index 2a83c27..1c6e7e3 100644 --- a/bdk/mem/sdram_lp0.c +++ b/bdk/mem/sdram_lp0.c @@ -2,7 +2,7 @@ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-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, @@ -17,16 +17,7 @@ #include #include #include - -/* - * This function reads SDRAM parameters from the common BCT format and - * writes them into PMC scratch registers (where the BootROM expects them - * on LP0 resume). - */ -void sdram_lp0_save_params(const void *params) -{ - struct sdram_params *sdram = (struct sdram_params *)params; - struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; +#include #define pack(src, src_bits, dst, dst_bits) { \ u32 mask = 0xffffffff >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \ @@ -46,6 +37,16 @@ void sdram_lp0_save_params(const void *params) /* 32 bits version c macro */ #define c32(value, pmcreg) pmc->pmcreg = value +/* + * This function reads SDRAM parameters from the common BCT format and + * writes them into PMC scratch registers (where the BootROM expects them + * on LP0 resume). + */ +static void _sdram_lp0_save_params_t210(const void *params) +{ + struct sdram_params_t210 *sdram = (struct sdram_params_t210 *)params; + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + //TODO: pkg1.1 (1.X - 3.X) reads them from MC. // Patch carveout parameters. /*sdram->McGeneralizedCarveout1Bom = 0; @@ -1124,3 +1125,414 @@ void sdram_lp0_save_params(const void *params) c32(0, scratch4); s(PllMStableTime, 9:0, scratch4, 9:0); } + +// #pragma GCC diagnostic ignored "-Wparentheses" + +// static void _sdram_lp0_save_params_t210b01(const void *params) +// { +// struct sdram_params_t210b01 *sdram = (struct sdram_params_t210b01 *)params; +// struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + +// u32 tmp = 0; + +// sdram->mc_generalized_carveout1_cfg0 = 0; +// sdram->mc_generalized_carveout2_cfg0 = 0; +// sdram->mc_generalized_carveout3_cfg0 = 0; +// sdram->mc_generalized_carveout4_cfg0 = 0; +// sdram->mc_generalized_carveout5_cfg0 = 0; + +// // Patch SDRAM parameters. +// u32 t0 = sdram->emc_swizzle_rank0_byte0 << 5 >> 29 > sdram->emc_swizzle_rank0_byte0 << 1 >> 29; +// u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->emc_swizzle_rank1_byte0 << 5 >> 29 > sdram->emc_swizzle_rank1_byte0 << 1 >> 29) << 4); +// u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->emc_swizzle_rank0_byte1 << 5 >> 29 > sdram->emc_swizzle_rank0_byte1 << 1 >> 29) << 1); +// u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->emc_swizzle_rank1_byte1 << 5 >> 29 > sdram->emc_swizzle_rank1_byte1 << 1 >> 29) << 5); +// u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->emc_swizzle_rank0_byte2 << 5 >> 29 > sdram->emc_swizzle_rank0_byte2 << 1 >> 29) << 2); +// u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->emc_swizzle_rank1_byte2 << 5 >> 29 > sdram->emc_swizzle_rank1_byte2 << 1 >> 29) << 6); +// u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->emc_swizzle_rank0_byte3 << 5 >> 29 > sdram->emc_swizzle_rank0_byte3 << 1 >> 29) << 3); +// u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->emc_swizzle_rank1_byte3 << 5 >> 29 > sdram->emc_swizzle_rank1_byte3 << 1 >> 29) << 7); +// sdram->swizzle_rank_byte_encode = t7; +// sdram->emc_bct_spare2 = 0x40000DD8; +// sdram->emc_bct_spare3 = t7; + +// s(emc_clock_source, 7:0, scratch6, 15:8); +// s(emc_clock_source_dll, 7:0, scratch6, 23:16); +// s(emc_clock_source, 31:29, scratch6, 26:24); +// s(emc_clock_source_dll, 31:29, scratch6, 29:27); +// s(emc_clock_source_dll, 11:10, scratch6, 31:30); +// pmc->scratch7 = (sdram->emc_rc << 24) | ((sdram->emc_zqcal_lpddr4_warm_boot << 27 >> 31 << 23) | ((sdram->emc_zqcal_lpddr4_warm_boot << 30 >> 31 << 22) | ((sdram->emc_zqcal_lpddr4_warm_boot << 21) & 0x3FFFFF | ((sdram->clk_rst_pllm_misc20_override << 20) & 0x1FFFFF | ((sdram->clk_rst_pllm_misc20_override << 28 >> 31 << 19) | ((sdram->clk_rst_pllm_misc20_override << 27 >> 31 << 18) | ((sdram->clk_rst_pllm_misc20_override << 26 >> 31 << 17) | ((sdram->clk_rst_pllm_misc20_override << 21 >> 31 << 16) | ((sdram->clk_rst_pllm_misc20_override << 20 >> 31 << 15) | ((sdram->clk_rst_pllm_misc20_override << 19 >> 31 << 14) | ((sdram->clk_rst_pllm_misc20_override << 18 >> 31 << 13) | ((sdram->emc_clock_source << 15 >> 31 << 12) | ((sdram->emc_clock_source << 11 >> 31 << 11) | ((sdram->emc_clock_source << 12 >> 31 << 10) | ((sdram->emc_clock_source << 6 >> 31 << 9) | ((sdram->emc_clock_source << 16 >> 31 << 8) | ((32 * sdram->emc_clock_source >> 31 << 7) | ((16 * sdram->emc_clock_source >> 31 << 6) | (16 * (sdram->emc_zqcal_lpddr4_warm_boot >> 30) | (4 * (sdram->clk_rst_pllm_misc20_override << 29 >> 30) | ((sdram->clk_rst_pllm_misc20_override << 22 >> 30) | 4 * (pmc->scratch7 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFFFFFF; +// pmc->scratch8 = (sdram->emc_pmacro_bg_bias_ctrl0 << 18 >> 30 << 30) | ((4 * pmc->scratch8) >> 2); +// pmc->scratch14 = ((u8)(sdram->emc_cfg_pipe_clk) << 31) | (2 * (((u8)(sdram->emc_fdpd_ctrl_cmd_no_ramp) << 30) | pmc->scratch14 & 0xBFFFFFFF) >> 1); +// s(emc_qrst, 6:0, scratch15, 26:20); +// s(emc_qrst, 20:16, scratch15, 31:27); +// s(emc_pmacro_cmd_tx_drive, 5:0, scratch16, 25:20); +// s(emc_pmacro_cmd_tx_drive, 13:8, scratch16, 31:26); +// pmc->scratch17 = (16 * sdram->emc_fbio_cfg8 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg8 >> 31 << 30) | ((sdram->emc_fbio_cfg8 << 6 >> 31 << 29) | ((sdram->emc_fbio_cfg8 << 7 >> 31 << 28) | ((sdram->emc_fbio_cfg8 << 8 >> 31 << 27) | ((sdram->emc_fbio_cfg8 << 9 >> 31 << 26) | ((sdram->emc_fbio_cfg8 << 10 >> 31 << 25) | ((sdram->emc_fbio_cfg8 << 11 >> 31 << 24) | ((sdram->emc_fbio_cfg8 << 12 >> 31 << 23) | ((sdram->emc_fbio_cfg8 << 13 >> 31 << 22) | ((sdram->emc_fbio_cfg8 << 14 >> 31 << 21) | ((sdram->emc_fbio_cfg8 << 15 >> 31 << 20) | pmc->scratch17 & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch18 = ((u16)(sdram->emc_txsr_dll) << 20) | pmc->scratch18 & 0xFFFFF; +// pmc->scratch19 = (sdram->emc_txdsrvttgen << 20) | pmc->scratch19 & 0xFFFFF; +// s32(emc_cfg_rsv, scratch22); +// s32(emc_auto_cal_config, scratch23); +// s32(emc_auto_cal_vref_sel0, scratch24); +// s32(emc_pmacro_brick_ctrl_rfu1, scratch25); +// s32(emc_pmacro_brick_ctrl_rfu2, scratch26); +// s32(emc_pmc_scratch1, scratch27); +// s32(emc_pmc_scratch2, scratch28); +// s32(emc_pmc_scratch3, scratch29); +// pmc->scratch30 = (sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl0 & 3 | 4 * (pmc->scratch30 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch31 = (sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl1 & 3 | 4 * (pmc->scratch31 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch32 = (sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl2 & 3 | 4 * (pmc->scratch32 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch33 = (sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl3 & 3 | 4 * (pmc->scratch33 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch40 = (sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl4 & 3 | 4 * (pmc->scratch40 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch42 = (sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl5 & 3 | 4 * (pmc->scratch42 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch44 = (sdram->mc_emem_arb_da_turns >> 24 << 24) | ((sdram->mc_emem_arb_da_turns >> 16 << 16) | ((sdram->mc_emem_arb_da_turns << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_turns & 0xFF | (pmc->scratch44 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; +// pmc->scratch64 = ((u16)(sdram->mc_emem_arb_misc2) << 31) | (2 * ((sdram->emc_fbio_spare << 30) | ((sdram->emc_fbio_spare << 24 >> 26 << 24) | ((sdram->emc_fbio_spare << 16 >> 24 << 16) | ((sdram->emc_fbio_spare << 8 >> 24 << 8) | ((sdram->emc_fbio_spare >> 24) | (pmc->scratch64 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch65 = ((u16)(sdram->mc_da_cfg0) << 31 >> 1) | ((2 * sdram->mc_emem_arb_misc0 >> 29 << 27) | ((16 * sdram->mc_emem_arb_misc0 >> 31 << 26) | ((32 * sdram->mc_emem_arb_misc0 >> 26 << 20) | ((sdram->mc_emem_arb_misc0 << 11 >> 27 << 15) | ((sdram->mc_emem_arb_misc0 << 17 >> 25 << 8) | ((u8)sdram->mc_emem_arb_misc0 | (pmc->scratch65 >> 8 << 8)) & 0xFFFF80FF) & 0xFFF07FFF) & 0xFC0FFFFF) & 0xFBFFFFFF) & 0xC7FFFFFF) & 0xBFFFFFFF; +// pmc->scratch66 = (sdram->emc_fdpd_ctrl_cmd >> 30 << 27) | ((4 * sdram->emc_fdpd_ctrl_cmd >> 31 << 26) | ((8 * sdram->emc_fdpd_ctrl_cmd >> 27 << 21) | ((sdram->emc_fdpd_ctrl_cmd << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_cmd << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_cmd << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_cmd | (pmc->scratch66 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xFBFFFFFF) & 0xE7FFFFFF; +// pmc->scratch67 = ((u8)(sdram->emc_burst_refresh_num) << 28) | ((16 * sdram->emc_auto_cal_config2 >> 30 << 26) | ((sdram->emc_auto_cal_config2 << 6 >> 30 << 24) | ((sdram->emc_auto_cal_config2 << 8 >> 30 << 22) | ((sdram->emc_auto_cal_config2 << 10 >> 30 << 20) | ((sdram->emc_auto_cal_config2 << 12 >> 30 << 18) | ((sdram->emc_auto_cal_config2 << 14 >> 30 << 16) | ((sdram->emc_auto_cal_config2 << 16 >> 30 << 14) | ((sdram->emc_auto_cal_config2 << 18 >> 30 << 12) | ((sdram->emc_auto_cal_config2 << 20 >> 30 << 10) | ((sdram->emc_auto_cal_config2 << 22 >> 30 << 8) | ((sdram->emc_auto_cal_config2 << 24 >> 30 << 6) | (16 * (sdram->emc_auto_cal_config2 << 26 >> 30) | (4 * (sdram->emc_auto_cal_config2 << 28 >> 30) | (sdram->emc_auto_cal_config2 & 3 | 4 * (pmc->scratch67 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; +// pmc->scratch68 = ((u8)(sdram->emc_tppd) << 28) | ((sdram->emc_cfg_dig_dll >> 31 << 27) | ((2 * sdram->emc_cfg_dig_dll >> 31 << 26) | ((16 * sdram->emc_cfg_dig_dll >> 31 << 25) | ((sdram->emc_cfg_dig_dll << 6 >> 22 << 15) | ((sdram->emc_cfg_dig_dll << 16 >> 31 << 14) | ((sdram->emc_cfg_dig_dll << 17 >> 31 << 13) | ((sdram->emc_cfg_dig_dll << 18 >> 30 << 11) | ((sdram->emc_cfg_dig_dll << 21 >> 29 << 8) | ((sdram->emc_cfg_dig_dll << 24 >> 30 << 6) | (32 * (sdram->emc_cfg_dig_dll << 26 >> 31) | (16 * (sdram->emc_cfg_dig_dll << 27 >> 31) | (8 * (sdram->emc_cfg_dig_dll << 28 >> 31) | (4 * (sdram->emc_cfg_dig_dll << 29 >> 31) | (2 * (sdram->emc_cfg_dig_dll << 30 >> 31) | (sdram->emc_cfg_dig_dll & 1 | 2 * (pmc->scratch68 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFF3F) & 0xFFFFF8FF) & 0xFFFFE7FF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFE007FFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; +// pmc->scratch69 = (sdram->emc_r2r << 28) | ((sdram->emc_fdpd_ctrl_dq >> 30 << 26) | ((8 * sdram->emc_fdpd_ctrl_dq >> 27 << 21) | ((sdram->emc_fdpd_ctrl_dq << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_dq << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_dq << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_dq | (pmc->scratch69 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; +// pmc->scratch70 = (sdram->emc_w2w << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_0 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ib_vref_dq_0 & 0x7F | (pmc->scratch70 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; +// pmc->scratch71 = (sdram->emc_pmacro_vttgen_ctrl0 << 12 >> 28 << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_1 << 17 >> 25 << 7) | ((pmc->scratch71 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dq_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; +// pmc->scratch72 = (((sdram->emc_pmacro_ib_vref_dqs_0 << 17 >> 25 << 7) | ((pmc->scratch72 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_0 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF | (sdram->emc_pmacro_ib_vref_dqs_0 << 9 >> 25 << 14)) & 0xF01FFFFF | (2 * sdram->emc_pmacro_ib_vref_dqs_0 >> 25 << 21); +// pmc->scratch73 = (2 * sdram->emc_pmacro_ib_vref_dqs_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 17 >> 25 << 7) | ((pmc->scratch73 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; +// pmc->scratch74 = (2 * sdram->emc_pmacro_ddll_short_cmd_0 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_0 & 0x7F | (pmc->scratch74 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; +// pmc->scratch75 = (2 * sdram->emc_pmacro_ddll_short_cmd_1 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_1 & 0x7F | (pmc->scratch75 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; +// pmc->scratch76 = (sdram->emc_rp << 26) | ((4 * sdram->emc_dll_cfg0 >> 31 << 25) | ((8 * sdram->emc_dll_cfg0 >> 31 << 24) | ((16 * sdram->emc_dll_cfg0 >> 28 << 20) | ((sdram->emc_dll_cfg0 << 8 >> 28 << 16) | ((sdram->emc_dll_cfg0 << 12 >> 28 << 12) | ((sdram->emc_dll_cfg0 << 16 >> 28 << 8) | ((sdram->emc_dll_cfg0 << 20 >> 24) | (pmc->scratch76 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; +// tmp = (sdram->emc_pmacro_tx_pwrd0 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd0 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd0 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd0 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd0 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd0 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd0 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd0 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd0 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd0 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd0 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd0 & 1 | 2 * (pmc->scratch77 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF; +// pmc->scratch77 = (sdram->emc_r2w << 26) | ((4 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd0 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd0 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd0 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd0 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd0 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd0 << 11 >> 31 << 17) | tmp & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; +// tmp = ((8 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd1 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd1 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd1 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd1 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd1 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd1 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd1 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd1 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd1 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd1 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd1 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd1 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd1 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd1 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd1 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd1 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd1 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd1 & 1 | 2 * (pmc->scratch78 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; +// pmc->scratch78 = (sdram->emc_w2r << 26) | ((4 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 25) | tmp) & 0x3FFFFFF; +// tmp = ((8 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd2 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd2 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd2 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd2 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd2 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd2 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd2 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd2 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd2 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd2 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd2 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd2 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd2 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd2 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd2 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd2 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd2 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd2 & 1 | 2 * (pmc->scratch79 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; +// pmc->scratch79 = (sdram->emc_r2p << 26) | ((4 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 25) | tmp) & 0x3FFFFFF; +// tmp = (sdram->emc_pmacro_tx_pwrd3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd3 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd3 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd3 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd3 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd3 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd3 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd3 & 1 | 2 * (pmc->scratch80 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF; +// pmc->scratch80 = ((u8)(sdram->emc_ccdmw) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd3 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd3 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd3 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd3 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd3 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd3 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd3 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd3 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd3 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd3 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd3 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd3 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd3 << 22 >> 31 << 9) | tmp & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; +// tmp = ((8 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd4 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd4 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd4 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd4 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd4 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd4 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd4 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd4 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd4 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd4 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd4 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd4 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd4 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd4 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd4 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd4 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd4 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd4 & 1 | 2 * (pmc->scratch81 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; +// pmc->scratch81 = ((u8)(sdram->emc_rd_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 25) | tmp) & 0x3FFFFFF; +// tmp = ((8 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd5 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd5 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd5 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd5 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd5 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd5 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd5 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd5 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd5 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd5 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd5 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd5 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd5 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd5 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd5 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd5 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd5 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd5 & 1 | 2 * (pmc->scratch82 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; +// pmc->scratch82 = ((u16)(sdram->emc_wr_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 25) | tmp) & 0x3FFFFFF; +// pmc->scratch83 = ((u8)(sdram->emc_config_sample_delay) << 25) | ((sdram->emc_auto_cal_channel >> 31 << 24) | ((2 * sdram->emc_auto_cal_channel >> 31 << 23) | ((4 * sdram->emc_auto_cal_channel >> 31 << 22) | ((16 * sdram->emc_auto_cal_channel >> 25 << 15) | ((sdram->emc_auto_cal_channel << 11 >> 27 << 10) | ((sdram->emc_auto_cal_channel << 20 >> 28 << 6) | (sdram->emc_auto_cal_channel & 0x3F | (pmc->scratch83 >> 6 << 6)) & 0xFFFFFC3F) & 0xFFFF83FF) & 0xFFC07FFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0x1FFFFFF; +// pmc->scratch84 = (sdram->emc_sel_dpd_ctrl << 13 >> 29 << 29) | ((sdram->emc_sel_dpd_ctrl << 23 >> 31 << 28) | ((sdram->emc_sel_dpd_ctrl << 26 >> 31 << 27) | ((sdram->emc_sel_dpd_ctrl << 27 >> 31 << 26) | ((sdram->emc_sel_dpd_ctrl << 28 >> 31 << 25) | ((sdram->emc_sel_dpd_ctrl << 29 >> 31 << 24) | ((4 * sdram->emc_pmacro_rx_term >> 26 << 18) | ((sdram->emc_pmacro_rx_term << 10 >> 26 << 12) | ((sdram->emc_pmacro_rx_term << 18 >> 26 << 6) | (sdram->emc_pmacro_rx_term & 0x3F | (pmc->scratch84 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; +// pmc->scratch85 = (4 * sdram->emc_obdly >> 30 << 30) | (4 * ((sdram->emc_obdly << 24) | ((4 * sdram->emc_pmacro_dq_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_dq_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_dq_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_dq_tx_drive & 0x3F | (pmc->scratch85 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); +// pmc->scratch86 = (sdram->emc_pmacro_vttgen_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_vttgen_ctrl1 << 16 >> 26 << 24) | ((4 * sdram->emc_pmacro_ca_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_ca_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_ca_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_ca_tx_drive & 0x3F | (pmc->scratch86 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); +// pmc->scratch87 = (sdram->emc_pmacro_vttgen_ctrl2 >> 16 << 24) | ((16 * sdram->emc_pmacro_zcrtl >> 30 << 22) | ((sdram->emc_pmacro_zcrtl << 6 >> 30 << 20) | ((sdram->emc_pmacro_zcrtl << 8 >> 30 << 18) | ((sdram->emc_pmacro_zcrtl << 10 >> 30 << 16) | ((sdram->emc_pmacro_zcrtl << 12 >> 30 << 14) | ((sdram->emc_pmacro_zcrtl << 14 >> 30 << 12) | ((sdram->emc_pmacro_zcrtl << 16 >> 30 << 10) | ((sdram->emc_pmacro_zcrtl << 18 >> 30 << 8) | ((sdram->emc_pmacro_zcrtl << 20 >> 30 << 6) | (16 * (sdram->emc_pmacro_zcrtl << 22 >> 30) | (4 * (sdram->emc_pmacro_zcrtl << 24 >> 30) | ((sdram->emc_pmacro_zcrtl << 26 >> 30) | 4 * (pmc->scratch87 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFFFFFF; +// pmc->scratch88 = (sdram->mc_emem_arb_timing_rc << 24) | ((sdram->emc_zcal_interval << 14) | ((sdram->emc_zcal_interval << 8 >> 18) | (pmc->scratch88 >> 14 << 14)) & 0xFF003FFF) & 0xFFFFFF; +// pmc->scratch89 = ((u16)(sdram->mc_emem_arb_rsv) << 24) | ((sdram->emc_data_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft0 << 26 >> 29) | (sdram->emc_data_brlshft0 & 7 | 8 * (pmc->scratch89 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0xFFFFFF; +// pmc->scratch90 = (sdram->emc_data_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft1 << 26 >> 29) | (sdram->emc_data_brlshft1 & 7 | 8 * (pmc->scratch90 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; +// pmc->scratch91 = (sdram->emc_dqs_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft0 << 26 >> 29) | (sdram->emc_dqs_brlshft0 & 7 | 8 * (pmc->scratch91 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; +// pmc->scratch92 = (sdram->emc_dqs_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft1 << 26 >> 29) | (sdram->emc_dqs_brlshft1 & 7 | 8 * (pmc->scratch92 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; +// pmc->scratch93 = (2 * sdram->emc_swizzle_rank0_byte0 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte0 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte0 & 7 | 8 * (pmc->scratch93 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; +// pmc->scratch94 = ((u8)(sdram->emc_cfg) << 27 >> 31 << 31) | (2 * ((sdram->emc_ras << 24) | ((2 * sdram->emc_swizzle_rank0_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte1 & 7 | 8 * (pmc->scratch94 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch95 = ((u8)(sdram->emc_cfg) << 26 >> 31 << 31) | (2 * ((sdram->emc_w2p << 24) | ((2 * sdram->emc_swizzle_rank0_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte2 & 7 | 8 * (pmc->scratch95 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch96 = ((u8)(sdram->emc_cfg) << 25 >> 31 << 31) | (2 * ((sdram->emc_qsafe << 24) | ((2 * sdram->emc_swizzle_rank0_byte3 >> 29 << 21) | (((sdram->emc_swizzle_rank0_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte3 & 7 | 8 * (pmc->scratch96 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank0_byte3 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch97 = ((u8)(sdram->emc_cfg) << 24 >> 31 << 31) | (2 * ((sdram->emc_rdv << 24) | ((2 * sdram->emc_swizzle_rank1_byte0 >> 29 << 21) | (((sdram->emc_swizzle_rank1_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte0 & 7 | 8 * (pmc->scratch97 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank1_byte0 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch98 = ((u16)(sdram->emc_cfg) << 23 >> 31 << 31) | (2 * (((u16)(sdram->emc_rw2pden) << 24) | ((2 * sdram->emc_swizzle_rank1_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte1 & 7 | 8 * (pmc->scratch98 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch99 = ((u16)(sdram->emc_cfg) << 22 >> 31 << 31) | (2 * ((sdram->emc_tfaw << 24) | ((2 * sdram->emc_swizzle_rank1_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte2 & 7 | 8 * (pmc->scratch99 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch100 = (sdram->emc_cfg << 13 >> 31 << 31) | (2 * ((sdram->emc_tclkstable << 24) | ((2 * sdram->emc_swizzle_rank1_byte3 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte3 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte3 & 7 | 8 * (pmc->scratch100 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); +// tmp = 2 * (((u8)(sdram->emc_trtm) << 24) | ((16 * sdram->emc_cfg_pipe2 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe2 >> 31 << 22) | ((sdram->emc_cfg_pipe2 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe2 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe2 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe2 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe2 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe2 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe2 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe2 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe2 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe2 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe2 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe2 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe2 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe2 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe2 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe2 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe2 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe2 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe2 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe2 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe2 << 30 >> 31) | (sdram->emc_cfg_pipe2 & 1 | 2 * (pmc->scratch101 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; +// pmc->scratch101 = (sdram->emc_cfg << 10 >> 31 << 31) | tmp; +// tmp = (2 * (pmc->scratch102 >> 1) | sdram->emc_cfg_pipe1 & 1) & 0xFFFFFFFD; +// pmc->scratch102 = (sdram->emc_cfg << 9 >> 31 << 31) | (2 * (((u8)(sdram->emc_twtm) << 24) | ((16 * sdram->emc_cfg_pipe1 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe1 >> 31 << 22) | ((sdram->emc_cfg_pipe1 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe1 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe1 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe1 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe1 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe1 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe1 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe1 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe1 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe1 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe1 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe1 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe1 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe1 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe1 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe1 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe1 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe1 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe1 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe1 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe1 << 30 >> 31) | tmp) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); +// tmp = 2 * (((u8)(sdram->emc_tratm) << 24) | ((sdram->emc_pmacro_ddll_pwrd0 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd0 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd0 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd0 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd0 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd0 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd0 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd0 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd0 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd0 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd0 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd0 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd0 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd0 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd0 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd0 << 30 >> 31) | 2 * (pmc->scratch103 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; +// pmc->scratch103 = (sdram->emc_cfg << 8 >> 31 << 31) | tmp; +// tmp = 2 * (((u8)(sdram->emc_twatm) << 24) | ((sdram->emc_pmacro_ddll_pwrd1 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd1 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd1 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd1 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd1 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd1 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd1 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd1 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd1 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd1 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd1 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd1 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd1 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd1 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd1 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd1 << 30 >> 31) | 2 * (pmc->scratch104 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; +// pmc->scratch104 = (sdram->emc_cfg << 7 >> 31 << 31) | tmp; +// tmp = (sdram->emc_pmacro_ddll_pwrd2 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd2 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd2 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd2 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd2 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd2 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd2 << 30 >> 31) | 2 * (pmc->scratch105 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF; +// pmc->scratch105 = (sdram->emc_cfg << 6 >> 31 << 31) | (2 * (((u8)(sdram->emc_tr2ref) << 24) | ((sdram->emc_pmacro_ddll_pwrd2 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd2 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd2 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd2 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd2 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd2 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd2 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd2 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd2 << 21 >> 31 << 7) | tmp & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch106 = (32 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_pdex2mrr) << 24) | ((8 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 23) | ((16 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 21) | ((sdram->emc_pmacro_ddll_periodic_offset << 6 >> 31 << 20) | ((sdram->emc_pmacro_ddll_periodic_offset << 7 >> 31 << 19) | ((sdram->emc_pmacro_ddll_periodic_offset << 8 >> 31 << 18) | ((sdram->emc_pmacro_ddll_periodic_offset << 9 >> 31 << 17) | ((sdram->emc_pmacro_ddll_periodic_offset << 10 >> 31 << 16) | ((sdram->emc_pmacro_ddll_periodic_offset << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_periodic_offset << 15 >> 31 << 14) | ((sdram->emc_pmacro_ddll_periodic_offset << 16 >> 31 << 13) | ((sdram->emc_pmacro_ddll_periodic_offset << 17 >> 31 << 12) | ((sdram->emc_pmacro_ddll_periodic_offset << 18 >> 31 << 11) | ((sdram->emc_pmacro_ddll_periodic_offset << 19 >> 31 << 10) | ((sdram->emc_pmacro_ddll_periodic_offset << 20 >> 31 << 9) | ((sdram->emc_pmacro_ddll_periodic_offset << 21 >> 31 << 8) | ((sdram->emc_pmacro_ddll_periodic_offset << 22 >> 31 << 7) | ((sdram->emc_pmacro_ddll_periodic_offset << 23 >> 31 << 6) | (sdram->emc_pmacro_ddll_periodic_offset & 0x3F | (pmc->scratch106 >> 6 << 6)) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch107 = (8 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_clken_override << 15 >> 31 << 30) | ((sdram->emc_clken_override << 23 >> 31 << 29) | ((sdram->emc_clken_override << 24 >> 31 << 28) | ((sdram->emc_clken_override << 25 >> 31 << 27) | ((sdram->emc_clken_override << 28 >> 31 << 26) | ((sdram->emc_clken_override << 29 >> 31 << 25) | ((sdram->emc_clken_override << 30 >> 31 << 24) | ((sdram->mc_emem_arb_da_covers << 8 >> 24 << 16) | ((sdram->mc_emem_arb_da_covers << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_covers & 0xFF | (pmc->scratch107 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch108 = (sdram->emc_rfc_pb << 23) | ((sdram->emc_xm2_comp_pad_ctrl >> 24 << 15) | ((sdram->emc_xm2_comp_pad_ctrl << 12 >> 24 << 7) | ((sdram->emc_xm2_comp_pad_ctrl << 20 >> 31 << 6) | (32 * (sdram->emc_xm2_comp_pad_ctrl << 22 >> 31) | (4 * (sdram->emc_xm2_comp_pad_ctrl << 25 >> 29) | (sdram->emc_xm2_comp_pad_ctrl & 3 | 4 * (pmc->scratch108 >> 2)) & 0xFFFFFFE3) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFF807F) & 0xFF807FFF) & 0x7FFFFF; +// pmc->scratch109 = (sdram->emc_cfg_update >> 31 << 31) | (2 * ((2 * sdram->emc_cfg_update >> 31 << 30) | ((4 * sdram->emc_cfg_update >> 31 << 29) | ((8 * sdram->emc_cfg_update >> 31 << 28) | ((sdram->emc_cfg_update << 21 >> 30 << 26) | ((sdram->emc_cfg_update << 23 >> 31 << 25) | ((sdram->emc_cfg_update << 29 >> 30 << 23) | ((sdram->emc_cfg_update << 22) & 0x7FFFFF | ((sdram->emc_auto_cal_config3 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config3 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config3 << 17 >> 25 << 7) | ((pmc->scratch109 >> 7 << 7) | sdram->emc_auto_cal_config3 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFE7FFFFF) & 0xFDFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch110 = (sdram->emc_rfc << 22) | ((sdram->emc_auto_cal_config4 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config4 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config4 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config4 & 0x7F | (pmc->scratch110 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; +// pmc->scratch111 = ((u16)(sdram->emc_txsr) << 22) | ((sdram->emc_auto_cal_config5 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config5 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config5 << 17 >> 25 << 7) | ((pmc->scratch111 >> 7 << 7) | sdram->emc_auto_cal_config5 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; +// pmc->scratch112 = (16 * sdram->emc_mc2emc_q >> 28 << 28) | ((sdram->emc_mc2emc_q << 21 >> 29 << 25) | ((sdram->emc_mc2emc_q << 22) & 0x1FFFFFF | ((sdram->emc_auto_cal_config6 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config6 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config6 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config6 & 0x7F | (pmc->scratch112 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xFFFFFFF; +// pmc->scratch113 = (sdram->mc_emem_arb_ring1_throttle << 11 >> 27 << 27) | ((sdram->mc_emem_arb_ring1_throttle << 22) | ((sdram->emc_auto_cal_config7 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config7 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config7 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config7 & 0x7F | (pmc->scratch113 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xF83FFFFF) & 0x7FFFFFF; +// pmc->scratch114 = (sdram->emc_auto_cal_config8 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config8 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config8 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config8 & 0x7F | (pmc->scratch114 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF; +// pmc->scratch115 = (4 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_ar2pden) << 22) | ((sdram->emc_fbio_cfg7 << 10 >> 30 << 20) | ((sdram->emc_fbio_cfg7 << 12 >> 31 << 19) | ((sdram->emc_fbio_cfg7 << 13 >> 31 << 18) | ((sdram->emc_fbio_cfg7 << 14 >> 31 << 17) | ((sdram->emc_fbio_cfg7 << 15 >> 31 << 16) | ((sdram->emc_fbio_cfg7 << 16 >> 31 << 15) | ((sdram->emc_fbio_cfg7 << 17 >> 31 << 14) | ((sdram->emc_fbio_cfg7 << 18 >> 31 << 13) | ((sdram->emc_fbio_cfg7 << 19 >> 31 << 12) | ((sdram->emc_fbio_cfg7 << 20 >> 31 << 11) | ((sdram->emc_fbio_cfg7 << 21 >> 31 << 10) | ((sdram->emc_fbio_cfg7 << 22 >> 31 << 9) | ((sdram->emc_fbio_cfg7 << 23 >> 31 << 8) | ((sdram->emc_fbio_cfg7 << 24 >> 31 << 7) | ((sdram->emc_fbio_cfg7 << 25 >> 31 << 6) | (32 * (sdram->emc_fbio_cfg7 << 26 >> 31) | (16 * (sdram->emc_fbio_cfg7 << 27 >> 31) | (8 * (sdram->emc_fbio_cfg7 << 28 >> 31) | (4 * (sdram->emc_fbio_cfg7 << 29 >> 31) | (2 * (sdram->emc_fbio_cfg7 << 30 >> 31) | (sdram->emc_fbio_cfg7 & 1 | 2 * (pmc->scratch115 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFCFFFFF) & 0x803FFFFF) >> 1); +// pmc->scratch123 = (2 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_rfc_slr << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_0 & 0x7FF | (pmc->scratch123 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); +// pmc->scratch124 = (sdram->emc_cfg >> 31 << 31) | (2 * ((4 * sdram->emc_ibdly >> 30 << 29) | ((sdram->emc_ibdly << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_1 & 0x7FF | (pmc->scratch124 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); +// pmc->scratch125 = (sdram->emc_fbio_cfg5 << 27 >> 31 << 31) | (2 * (((u16)(sdram->mc_emem_arb_timing_rfcpb) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_2 & 0x7FF | (pmc->scratch125 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); +// pmc->scratch126 = (sdram->emc_fbio_cfg5 << 16 >> 29 << 29) | ((sdram->emc_auto_cal_config9 << 25 >> 31 << 28) | ((sdram->emc_auto_cal_config9 << 26 >> 31 << 27) | ((sdram->emc_auto_cal_config9 << 27 >> 31 << 26) | ((sdram->emc_auto_cal_config9 << 28 >> 31 << 25) | ((sdram->emc_auto_cal_config9 << 29 >> 31 << 24) | ((sdram->emc_auto_cal_config9 << 30 >> 31 << 23) | ((sdram->emc_auto_cal_config9 << 22) & 0x7FFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_3 & 0x7FF | (pmc->scratch126 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; +// pmc->scratch127 = ((u8)(sdram->emc_cfg2) << 26 >> 29 << 29) | ((sdram->emc_rdv_mask << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_4 & 0x7FF | (pmc->scratch127 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch128 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 27 >> 29 << 29) | (((u8)(sdram->emc_rdv_early_mask) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_5 & 0x7FF | (pmc->scratch128 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch129 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_rdv_early << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_0 & 0x7FF | (pmc->scratch129 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch130 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 17 >> 29 << 29) | ((4 * sdram->emc_quse_width >> 31 << 28) | ((8 * sdram->emc_quse_width >> 31 << 27) | ((sdram->emc_quse_width << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_1 & 0x7FF | (pmc->scratch130 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; +// pmc->scratch131 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 12 >> 29 << 29) | (((u16)(sdram->emc_pmacro_ddll_short_cmd_2) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_2 & 0x7FF | (pmc->scratch131 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch132 = (sdram->emc_pmacro_data_pad_tx_ctrl << 27 >> 29 << 29) | ((sdram->emc_pmacro_cmd_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_cmd_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_3 & 0x7FF | (pmc->scratch132 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; +// pmc->scratch133 = (sdram->emc_pmacro_data_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_pmacro_data_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_data_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_data_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_data_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_4 & 0x7FF | (pmc->scratch133 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; +// pmc->scratch134 = (sdram->emc_pmacro_data_pad_tx_ctrl << 17 >> 29 << 29) | ((sdram->mc_emem_arb_timing_rp << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_5 & 0x7FF | (pmc->scratch134 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch135 = (sdram->emc_pmacro_data_pad_tx_ctrl << 12 >> 29 << 29) | ((sdram->mc_emem_arb_timing_ras << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 & 0x7FF | (pmc->scratch135 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; +// pmc->scratch136 = (sdram->emc_fbio_cfg5 << 23 >> 31 << 31) | (2 * ((sdram->emc_cfg << 14 >> 30 << 29) | ((sdram->mc_emem_arb_timing_faw << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 & 0x7FF | (pmc->scratch136 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); +// pmc->scratch137 = (sdram->emc_fbio_cfg5 << 21 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 29) | ((sdram->mc_emem_arb_timing_rap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 & 0x7FF | (pmc->scratch137 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); +// pmc->scratch138 = (sdram->emc_fbio_cfg5 << 19 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 28 >> 30 << 29) | ((sdram->mc_emem_arb_timing_wap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 & 0x7FF | (pmc->scratch138 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); +// pmc->scratch139 = (sdram->emc_fbio_cfg5 << 7 >> 31 << 31) | (2 * ((16 * sdram->emc_cfg2 >> 30 << 29) | (((u8)(sdram->mc_emem_arb_timing_r2w) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 & 0x7FF | (pmc->scratch139 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); +// pmc->scratch140 = (16 * sdram->emc_fbio_cfg5 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg5 >> 31 << 30) | ((sdram->emc_fbio_cfg5 << 6 >> 31 << 29) | (((u8)(sdram->mc_emem_arb_timing_w2r) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 & 0x7FF | (pmc->scratch140 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch141 = (sdram->emc_fbio_cfg5 << 8 >> 28 << 28) | (((u16)(sdram->emc_wdv) << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 & 0x7FF | (pmc->scratch141 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xFFFFFFF; +// pmc->scratch142 = ((u8)(sdram->emc_cfg2) << 31) | (2 * ((sdram->emc_fbio_cfg5 >> 31 << 30) | ((2 * sdram->emc_fbio_cfg5 >> 31 << 29) | ((8 * sdram->emc_fbio_cfg5 >> 31 << 28) | ((sdram->emc_quse << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 & 0x7FF | (pmc->scratch142 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch143 = (((u16)(sdram->emc_cfg2) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg2) << 24) >> 31 << 30) | ((((u16)(sdram->emc_cfg2) << 29) >> 31 << 29) | ((((u16)(sdram->emc_cfg2) << 30) >> 31 << 28) | (((u8)(sdram->emc_pdex2wr) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 & 0x7FF | (pmc->scratch143 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch144 = (sdram->emc_cfg2 << 15 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 16 >> 31 << 30) | ((sdram->emc_cfg2 << 17 >> 31 << 29) | ((sdram->emc_cfg2 << 20 >> 31 << 28) | (((u8)(sdram->emc_pdex2rd) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 & 0x7FF | (pmc->scratch144 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch145 = (sdram->emc_cfg2 << 7 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 8 >> 31 << 30) | ((sdram->emc_cfg2 << 9 >> 31 << 29) | ((sdram->emc_cfg2 << 11 >> 31 << 28) | (((u16)(sdram->emc_pdex2che) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 & 0x7FF | (pmc->scratch145 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch146 = (2 * sdram->emc_cfg2 >> 31 << 31) | (2 * ((4 * sdram->emc_cfg2 >> 31 << 30) | (((sdram->emc_cfg2 << 6 >> 31 << 28) | (((u8)(sdram->emc_pchg2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 & 0x7FF | (pmc->scratch146 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (8 * sdram->emc_cfg2 >> 31 << 29)) & 0xBFFFFFFF) >> 1); +// pmc->scratch147 = (((u8)(sdram->emc_cfg_pipe) << 29) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 30) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 31) >> 2) | ((sdram->emc_cfg2 >> 31 << 28) | (((u16)(sdram->emc_act2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch147 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch148 = (((u8)(sdram->emc_cfg_pipe) << 25) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 26) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 27) >> 31 << 29) | ((((u8)(sdram->emc_cfg_pipe) << 28) >> 31 << 28) | (((u16)(sdram->emc_cke2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch148 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch149 = (((u16)(sdram->emc_cfg_pipe) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg_pipe) << 22) >> 31 << 30) | ((((u16)(sdram->emc_cfg_pipe) << 23) >> 31 << 29) | ((((u16)(sdram->emc_cfg_pipe) << 24) >> 31 << 28) | ((sdram->emc_tcke << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch149 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch150 = (sdram->emc_cfg_pipe << 13 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 14 >> 31 << 30) | (((sdram->emc_cfg_pipe << 20 >> 31 << 28) | ((sdram->emc_trpab << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch150 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (sdram->emc_cfg_pipe << 15 >> 31 << 29)) & 0xBFFFFFFF) >> 1); +// pmc->scratch151 = (sdram->emc_cfg_pipe << 9 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 10 >> 31 << 30) | ((sdram->emc_cfg_pipe << 11 >> 31 << 29) | ((sdram->emc_cfg_pipe << 12 >> 31 << 28) | ((sdram->emc_einput << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 & 0x7FF | (pmc->scratch151 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch152 = (32 * sdram->emc_cfg_pipe >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 6 >> 31 << 30) | ((sdram->emc_cfg_pipe << 7 >> 31 << 29) | ((sdram->emc_cfg_pipe << 8 >> 31 << 28) | ((sdram->emc_einput_duration << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 & 0x7FF | (pmc->scratch152 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch153 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 31) >> 2) | ((16 * sdram->emc_cfg_pipe >> 31 << 28) | ((sdram->emc_puterm_extra << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch153 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch154 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 26) >> 31 << 30) | (((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 28) >> 31 << 28) | ((sdram->emc_tckesr << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch154 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 27) >> 31 << 29)) & 0xBFFFFFFF) >> 1); +// pmc->scratch155 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 24) >> 31 << 28) | ((sdram->emc_tpd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch155 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch156 = (sdram->emc_pmacro_tx_sel_clk_src0 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 15 >> 31 << 28) | ((sdram->emc_wdv_mask << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch156 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch157 = (sdram->emc_pmacro_tx_sel_clk_src0 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 11 >> 31 << 28) | (((u16)(sdram->emc_wdv_chk) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 & 0x7FF | (pmc->scratch157 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch158 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src0 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 7 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft0) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft0) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 & 0x7FF | (pmc->scratch158 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch159 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 27) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 28) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 29) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 30) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft1) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft1) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch159 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch160 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 23) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 24) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 25) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 26) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft2) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft2) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch160 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch161 = (sdram->emc_pmacro_tx_sel_clk_src1 << 14 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 15 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 21 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 22 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft3) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch161 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch162 = (sdram->emc_pmacro_tx_sel_clk_src1 << 10 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 11 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 12 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 13 >> 31 << 28) | (((u16)(sdram->emc_wev) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch162 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch163 = (sdram->emc_pmacro_tx_sel_clk_src1 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 7 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 8 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 9 >> 31 << 28) | (((u16)(sdram->emc_wsv) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch163 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch164 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 31) >> 2) | ((32 * sdram->emc_pmacro_tx_sel_clk_src1 >> 31 << 28) | (((u8)(sdram->emc_cfg3) << 25 >> 29 << 25) | (((u8)(sdram->emc_cfg3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch164 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch165 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 26) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 27) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 28) >> 31 << 28) | ((sdram->emc_puterm_width << 23) & 0xFFFFFFF | ((sdram->emc_puterm_width >> 31 << 22) | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch165 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xF07FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch166 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 24) >> 31 << 28) | ((sdram->mc_emem_arb_timing_rcd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch166 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch167 = (sdram->emc_pmacro_tx_sel_clk_src3 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 15 >> 31 << 28) | (((u16)(sdram->mc_emem_arb_timing_ccdmw) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ddll_long_cmd_0 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_0 & 0x7FF | (pmc->scratch167 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch168 = (sdram->emc_pmacro_tx_sel_clk_src3 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 11 >> 31 << 28) | ((sdram->mc_emem_arb_override << 28 >> 31 << 27) | (((sdram->mc_emem_arb_override << 21 >> 31 << 25) | ((sdram->mc_emem_arb_override << 15 >> 31 << 24) | ((32 * sdram->mc_emem_arb_override >> 31 << 23) | ((16 * sdram->mc_emem_arb_override >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_1 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_1 & 0x7FF | (pmc->scratch168 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF | (sdram->mc_emem_arb_override << 27 >> 31 << 26)) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch169 = ((u16)(sdram->emc_rext) << 27) | (((u16)(sdram->emc_rrd) << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_2 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_2 & 0x7FF | (pmc->scratch169 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; +// pmc->scratch170 = ((u16)(sdram->emc_wext) << 27) | ((sdram->emc_tclkstop << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_3 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_3 & 0x7FF | (pmc->scratch170 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; +// tmp = (32 * sdram->emc_pmacro_perbit_fgcg_ctrl0 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl0 & 1 | 2 * (pmc->scratch171 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF; +// pmc->scratch171 = (sdram->emc_we_duration << 27) | ((sdram->emc_ref_ctrl2 >> 31 << 26) | ((32 * sdram->emc_ref_ctrl2 >> 29 << 23) | ((sdram->emc_ref_ctrl2 << 22) & 0x7FFFFF | tmp & 0xFFBFFFFF) & 0xFC7FFFFF) & 0xFBFFFFFF) & 0x7FFFFFF; +// tmp = (sdram->emc_pmacro_pad_cfg_ctrl << 22 >> 31 << 28) | ((sdram->emc_pmacro_pad_cfg_ctrl << 27) & 0xFFFFFFF | ((sdram->emc_ws_duration << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl1 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl1 & 1 | 2 * (pmc->scratch172 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; +// pmc->scratch172 = (sdram->emc_pmacro_pad_cfg_ctrl << 14 >> 30 << 30) | (4 * ((sdram->emc_pmacro_pad_cfg_ctrl << 18 >> 31 << 29) | tmp & 0xDFFFFFFF) >> 2); +// pmc->scratch173 = ((u8)(sdram->mc_emem_arb_timing_r2r) << 27) | ((sdram->mc_emem_arb_timing_rrd << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl2 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl2 & 1 | 2 * (pmc->scratch173 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0x7FFFFFF; +// tmp = 32 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl3 & 1 | 2 * (pmc->scratch174 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; +// pmc->scratch174 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30 >> 31 << 31) | (2 * (((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30) | ((32 * sdram->emc_pmacro_tx_sel_clk_src3 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 6 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 7 >> 31 << 27) | (((u8)(sdram->mc_emem_arb_timing_w2w) << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl3 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 25 >> 31 << 6) | tmp & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 28 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 29 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl4 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl4 & 1 | 2 * (pmc->scratch175 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF; +// pmc->scratch175 = (sdram->emc_pmacro_tx_sel_clk_src2 << 15 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 21 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 22 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 23 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 24 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 25 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 26 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 27 >> 31 << 24) | tmp & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 12 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 13 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 14 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl5 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl5 & 1 | 2 * (pmc->scratch176 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; +// pmc->scratch176 = (32 * sdram->emc_pmacro_tx_sel_clk_src2 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 6 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 8 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 9 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 10 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 11 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch177 = (sdram->emc_pmacro_tx_sel_clk_src4 << 22 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 23 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 24 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 25 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 26 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 27 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 28 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 29 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 30 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 22) & 0x7FFFFF | ((sdram->mc_emem_arb_cfg >> 28 << 18) | ((16 * sdram->mc_emem_arb_cfg >> 28 << 14) | ((sdram->mc_emem_arb_cfg << 11 >> 27 << 9) | (sdram->mc_emem_arb_cfg & 0x1FF | (pmc->scratch177 >> 9 << 9)) & 0xFFFFC1FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch178 = (sdram->emc_pmacro_tx_sel_clk_src4 << 7 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 8 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 9 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 10 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 11 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 12 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 13 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 14 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 15 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 21 >> 31 << 22) | ((sdram->mc_emem_arb_misc1 >> 28 << 18) | ((sdram->mc_emem_arb_misc1 << 6 >> 30 << 16) | ((sdram->mc_emem_arb_misc1 << 8 >> 29 << 13) | (16 * (sdram->mc_emem_arb_misc1 << 19 >> 23) | (8 * (sdram->mc_emem_arb_misc1 << 28 >> 31) | (4 * (sdram->mc_emem_arb_misc1 << 29 >> 31) | (2 * (sdram->mc_emem_arb_misc1 << 30 >> 31) | (sdram->mc_emem_arb_misc1 & 1 | 2 * (pmc->scratch178 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFE00F) & 0xFFFF1FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch179 = (sdram->emc_odt_write >> 31 << 31) | (2 * ((sdram->emc_odt_write << 20 >> 28 << 27) | ((sdram->emc_odt_write << 26 >> 31 << 26) | ((sdram->emc_odt_write << 27 >> 31 << 25) | ((sdram->emc_odt_write << 21) & 0x1FFFFFF | ((32 * sdram->emc_mrs_wait_cnt2 >> 21 << 10) | (sdram->emc_mrs_wait_cnt2 & 0x3FF | (pmc->scratch179 >> 10 << 10)) & 0xFFE003FF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); +// pmc->scratch180 = (sdram->emc_pmacro_ib_rxrt << 21) | ((32 * sdram->emc_mrs_wait_cnt >> 21 << 10) | (sdram->emc_mrs_wait_cnt & 0x3FF | (pmc->scratch180 >> 10 << 10)) & 0xFFE003FF) & 0x1FFFFF; +// pmc->scratch181 = ((u16)(sdram->emc_pmacro_ddll_long_cmd_4) << 21) | sdram->emc_auto_cal_interval & 0x1FFFFF; +// pmc->scratch182 = (sdram->mc_emem_arb_outstanding_req >> 31 << 31) | (2 * ((2 * sdram->mc_emem_arb_outstanding_req >> 31 << 30) | ((sdram->mc_emem_arb_outstanding_req << 23 >> 2) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 9 >> 25 << 14) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 17 >> 25 << 7) | (sdram->emc_emem_arb_refpb_hp_ctrl & 0x7F | (pmc->scratch182 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xC01FFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch183 = (4 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl0 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl0 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl0 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl0 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl0 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl0 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl0 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl0 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl0 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl0 << 20) & 0x1FFFFF | ((4 * sdram->emc_xm2_comp_pad_ctrl2 >> 26 << 14) | ((sdram->emc_xm2_comp_pad_ctrl2 << 10 >> 30 << 12) | ((sdram->emc_xm2_comp_pad_ctrl2 << 14 >> 31 << 11) | ((sdram->emc_xm2_comp_pad_ctrl2 << 15 >> 31 << 10) | ((sdram->emc_xm2_comp_pad_ctrl2 << 16 >> 30 << 8) | ((sdram->emc_xm2_comp_pad_ctrl2 << 18 >> 30 << 6) | (4 * (sdram->emc_xm2_comp_pad_ctrl2 << 26 >> 28) | (sdram->emc_xm2_comp_pad_ctrl2 & 3 | 4 * (pmc->scratch183 >> 2)) & 0xFFFFFFC3) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFF03FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch184 = (4 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl1 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl1 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl1 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl1 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl1 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl1 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl1 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl1 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl1 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl1 << 20) & 0x1FFFFF | ((sdram->emc_cfg_dig_dll_1 << 12 >> 28 << 16) | ((sdram->emc_cfg_dig_dll_1 << 16 >> 28 << 12) | ((sdram->emc_cfg_dig_dll_1 << 20 >> 26 << 6) | (2 * (sdram->emc_cfg_dig_dll_1 << 26 >> 27) | (sdram->emc_cfg_dig_dll_1 & 1 | 2 * (pmc->scratch184 >> 1)) & 0xFFFFFFC1) & 0xFFFFF03F) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch185 = (4 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl2 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl2 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl2 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl2 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl2 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl2 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl2 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl2 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl2 << 20) & 0x1FFFFF | ((sdram->emc_quse_brlshft0 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft0 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft0 << 22 >> 27) | (sdram->emc_quse_brlshft0 & 0x1F | 32 * (pmc->scratch185 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch186 = (sdram->emc_pmacro_dsr_vttgen_ctrl0 >> 8 << 24) | ((sdram->emc_pmacro_dsr_vttgen_ctrl0 << 20) | ((sdram->emc_quse_brlshft1 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft1 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft1 << 22 >> 27) | (sdram->emc_quse_brlshft1 & 0x1F | 32 * (pmc->scratch186 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFF0FFFFF) & 0xFFFFFF; +// pmc->scratch187 = (sdram->emc_pmacro_perbit_rfu1_ctrl0 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft2 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft2 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft2 << 22 >> 27) | (sdram->emc_quse_brlshft2 & 0x1F | 32 * (pmc->scratch187 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch188 = (sdram->emc_pmacro_perbit_rfu1_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft3 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft3 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft3 << 22 >> 27) | (sdram->emc_quse_brlshft3 & 0x1F | 32 * (pmc->scratch188 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); +// pmc->scratch189 = (sdram->emc_trefbw << 18) | ((sdram->emc_dbg >> 31 << 17) | ((2 * sdram->emc_dbg >> 31 << 16) | ((4 * sdram->emc_dbg >> 31 << 15) | ((8 * sdram->emc_dbg >> 31 << 14) | ((16 * sdram->emc_dbg >> 30 << 12) | ((sdram->emc_dbg << 6 >> 31 << 11) | ((sdram->emc_dbg << 7 >> 31 << 10) | ((sdram->emc_dbg << 18 >> 31 << 9) | ((sdram->emc_dbg << 19 >> 31 << 8) | ((sdram->emc_dbg << 20 >> 31 << 7) | ((sdram->emc_dbg << 21 >> 31 << 6) | (32 * (sdram->emc_dbg << 22 >> 31) | (16 * (sdram->emc_dbg << 27 >> 31) | (8 * (sdram->emc_dbg << 28 >> 31) | (4 * (sdram->emc_dbg << 29 >> 31) | (2 * (sdram->emc_dbg << 30 >> 31) | (sdram->emc_dbg & 1 | 2 * (pmc->scratch189 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0x3FFFF; +// pmc->scratch191 = (sdram->emc_qpop << 9 >> 25 << 25) | ((sdram->emc_qpop << 18) | ((sdram->emc_zcal_wait_cnt >> 31 << 17) | ((sdram->emc_zcal_wait_cnt << 10 >> 26 << 11) | (sdram->emc_zcal_wait_cnt & 0x7FF | (pmc->scratch191 >> 11 << 11)) & 0xFFFE07FF) & 0xFFFDFFFF) & 0xFE03FFFF) & 0x1FFFFFF; +// pmc->scratch192 = (sdram->emc_pmacro_tx_sel_clk_src4 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_auto_cal_common << 15 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_common << 18 >> 26 << 24) | ((sdram->emc_pmacro_auto_cal_common << 18) & 0xFFFFFF | ((sdram->emc_zcal_mrw_cmd >> 30 << 16) | ((sdram->emc_zcal_mrw_cmd << 8 >> 24 << 8) | (sdram->emc_zcal_mrw_cmd & 0xFF | (pmc->scratch192 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFCFFFF) & 0xFF03FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); +// tmp = (sdram->emc_dll_cfg1 << 7 >> 31 << 17) | ((sdram->emc_dll_cfg1 << 10 >> 31 << 16) | ((sdram->emc_dll_cfg1 << 11 >> 31 << 15) | ((sdram->emc_dll_cfg1 << 14 >> 30 << 13) | ((sdram->emc_dll_cfg1 << 18 >> 31 << 12) | ((sdram->emc_dll_cfg1 << 19 >> 31 << 11) | ((pmc->scratch193 >> 11 << 11) | sdram->emc_dll_cfg1 & 0x7FF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFF9FFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF; +// pmc->scratch193 = (sdram->emc_pmacro_tx_sel_clk_src5 << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src4 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 18) & 0xFFFFF | tmp & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl2 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch194 = (sdram->emc_pmacro_tx_sel_clk_src5 << 29 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 30 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 14 >> 30 << 24) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 18) & 0xFFFFF | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_cmd_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch194 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 26 >> 30 << 22)) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch195 = (sdram->emc_pmacro_tx_sel_clk_src5 << 27 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 28 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 18) & 0xFFFFF | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_data_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch195 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl4 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch196 = (sdram->emc_emem_arb_refpb_bank_ctrl >> 31 << 31) | (2 * ((sdram->emc_emem_arb_refpb_bank_ctrl << 17 >> 25 << 24) | ((sdram->emc_emem_arb_refpb_bank_ctrl << 17) & 0xFFFFFF | ((sdram->emc_dyn_self_ref_control >> 31 << 16) | (sdram->emc_dyn_self_ref_control & 0xFFFF | (pmc->scratch196 >> 16 << 16)) & 0xFFFEFFFF) & 0xFF01FFFF) & 0x80FFFFFF) >> 1); +// pmc->scratch197 = (sdram->emc_pmacro_tx_sel_clk_src5 << 24 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 25 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 26 >> 31 << 29) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 10 >> 30 << 27) | (((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 14 >> 30 << 23) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 26 >> 30 << 21) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 28 >> 30 << 19) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 17) & 0x7FFFF | ((16 * sdram->emc_pmacro_cmd_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_cmd_pad_rx_ctrl & 3 | 4 * (pmc->scratch197 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFF9FFFF) & 0xFFE7FFFF) & 0xFF9FFFFF) & 0xFE7FFFFF) & 0xF9FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl5 << 12 >> 30 << 25)) & 0xE7FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch198 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src5 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 7 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 8 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 9 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 10 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 11 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 12 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 13 >> 31 << 22) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 14 >> 31 << 21) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 15 >> 31 << 20) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 21 >> 31 << 19) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 22 >> 31 << 18) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 23 >> 31 << 17) | ((16 * sdram->emc_pmacro_data_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_data_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_data_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_data_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_data_pad_rx_ctrl & 3 | 4 * (pmc->scratch198 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch199 = (8 * sdram->emc_cmd_q >> 27 << 27) | ((sdram->emc_cmd_q << 17 >> 29 << 24) | ((sdram->emc_cmd_q << 21 >> 29 << 21) | ((sdram->emc_cmd_q << 16) & 0x1FFFFF | (((u16)(sdram->emc_refresh) << 16 >> 22 << 6) | (sdram->emc_refresh & 0x3F | (pmc->scratch199 >> 6 << 6)) & 0xFFFF003F) & 0xFFE0FFFF) & 0xFF1FFFFF) & 0xF8FFFFFF) & 0x7FFFFFF; +// pmc->scratch210 = (sdram->emc_auto_cal_vref_sel1 << 16 >> 31 << 31) | (2 * ((sdram->emc_auto_cal_vref_sel1 << 17 >> 25 << 24) | ((sdram->emc_auto_cal_vref_sel1 << 24 >> 31 << 23) | ((sdram->emc_auto_cal_vref_sel1 << 16) & 0x7FFFFF | (sdram->emc_acpd_control & 0xFFFF | (pmc->scratch210 >> 16 << 16)) & 0xFF80FFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); +// tmp = 8 * (sdram->emc_pmacro_auto_cal_cfg0 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg0 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg0 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg0 & 1 | 2 * (pmc->scratch211 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7; +// tmp = (sdram->emc_pmacro_auto_cal_cfg1 << 7 >> 31 << 28) | ((sdram->emc_pmacro_auto_cal_cfg1 << 12 >> 31 << 27) | ((sdram->emc_pmacro_auto_cal_cfg1 << 13 >> 31 << 26) | ((sdram->emc_pmacro_auto_cal_cfg1 << 14 >> 31 << 25) | ((sdram->emc_pmacro_auto_cal_cfg1 << 15 >> 31 << 24) | ((sdram->emc_pmacro_auto_cal_cfg1 << 20 >> 31 << 23) | ((sdram->emc_pmacro_auto_cal_cfg1 << 21 >> 31 << 22) | ((sdram->emc_pmacro_auto_cal_cfg1 << 22 >> 31 << 21) | ((sdram->emc_pmacro_auto_cal_cfg1 << 23 >> 31 << 20) | ((sdram->emc_pmacro_auto_cal_cfg1 << 28 >> 31 << 19) | ((sdram->emc_pmacro_auto_cal_cfg1 << 29 >> 31 << 18) | ((sdram->emc_pmacro_auto_cal_cfg1 << 30 >> 31 << 17) | ((sdram->emc_pmacro_auto_cal_cfg1 << 16) & 0x1FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg0 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg0 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg0 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg0 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg0 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg0 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg0 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg0 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg0 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg0 << 23 >> 31) | tmp & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; +// pmc->scratch211 = (16 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 31) | (2 * ((32 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_cfg1 << 6 >> 31 << 29) | tmp & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->scratch212 = (sdram->emc_xm2_comp_pad_ctrl3 << 8 >> 28 << 28) | ((sdram->emc_xm2_comp_pad_ctrl3 << 14 >> 31 << 27) | ((sdram->emc_xm2_comp_pad_ctrl3 << 15 >> 31 << 26) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16 >> 30 << 24) | ((sdram->emc_xm2_comp_pad_ctrl3 << 18 >> 30 << 22) | ((sdram->emc_xm2_comp_pad_ctrl3 << 26 >> 28 << 18) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16) & 0x3FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg2 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg2 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg2 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg2 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg2 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg2 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg2 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg2 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg2 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg2 << 23 >> 31) | (8 * (sdram->emc_pmacro_auto_cal_cfg2 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg2 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg2 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg2 & 1 | 2 * (pmc->scratch212 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; +// pmc->scratch213 = ((u16)(sdram->emc_prerefresh_req_cnt) << 16) | (u16)(sdram->emc_cfg_dig_dll_period); +// pmc->scratch214 = (sdram->emc_pmacro_data_pi_ctrl << 10 >> 26 << 26) | ((sdram->emc_pmacro_data_pi_ctrl << 19 >> 31 << 25) | ((sdram->emc_pmacro_data_pi_ctrl << 20 >> 28 << 21) | ((sdram->emc_pmacro_data_pi_ctrl << 27 >> 31 << 20) | ((sdram->emc_pmacro_data_pi_ctrl << 16) & 0xFFFFF | ((sdram->emc_pmacro_ddll_bypass >> 31 << 15) | ((2 * sdram->emc_pmacro_ddll_bypass >> 31 << 14) | ((4 * sdram->emc_pmacro_ddll_bypass >> 31 << 13) | ((16 * sdram->emc_pmacro_ddll_bypass >> 31 << 12) | ((32 * sdram->emc_pmacro_ddll_bypass >> 31 << 11) | ((sdram->emc_pmacro_ddll_bypass << 6 >> 31 << 10) | ((sdram->emc_pmacro_ddll_bypass << 7 >> 31 << 9) | ((sdram->emc_pmacro_ddll_bypass << 15 >> 31 << 8) | ((sdram->emc_pmacro_ddll_bypass << 16 >> 31 << 7) | ((sdram->emc_pmacro_ddll_bypass << 17 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_bypass << 18 >> 31) | (16 * (sdram->emc_pmacro_ddll_bypass << 20 >> 31) | (8 * (sdram->emc_pmacro_ddll_bypass << 21 >> 31) | (4 * (sdram->emc_pmacro_ddll_bypass << 22 >> 31) | (2 * (sdram->emc_pmacro_ddll_bypass << 23 >> 31) | (sdram->emc_pmacro_ddll_bypass & 1 | 2 * (pmc->scratch214 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; +// pmc->scratch215 = (sdram->emc_pmacro_cmd_pi_ctrl << 10 >> 26 << 10) | ((sdram->emc_pmacro_cmd_pi_ctrl << 19 >> 31 << 9) | (32 * (sdram->emc_pmacro_cmd_pi_ctrl << 20 >> 28) | (16 * (sdram->emc_pmacro_cmd_pi_ctrl << 27 >> 31) | (sdram->emc_pmacro_cmd_pi_ctrl & 0xF | 16 * (pmc->scratch215 >> 4)) & 0xFFFFFFEF) & 0xFFFFFE1F) & 0xFFFFFDFF) & 0xFFFF03FF; +// tmp = (sdram->emc_pmacro_data_pad_tx_ctrl << 7 >> 31 << 24) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 8 >> 31 << 23) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 9 >> 31 << 22) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 10 >> 31 << 21) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15 >> 31 << 20) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 16 >> 31 << 19) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 21 >> 31 << 18) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 25 >> 31 << 17) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 26 >> 31 << 16) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15) & 0xFFFF | ((2 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 14) | ((4 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 13) | ((8 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 12) | ((16 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 11) | ((32 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 6 >> 31 << 9) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 7 >> 31 << 8) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 8 >> 31 << 7) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 9 >> 31 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 10 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 15 >> 31) | (8 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 16 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 21 >> 31) | (2 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 25 >> 31) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 26 >> 31) | 2 * (pmc->scratch216 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; + +// s(emc_pin_gpio, 1:0, scratch9, 31:30); +// s(emc_pin_gpio_enable, 1:0, scratch10, 31:30); +// s(emc_dev_select, 1:0, scratch11, 31:30); +// s(emc_zcal_warm_cold_boot_enables, 1:0, scratch12, 31:30); +// s(emc_cfg_dig_dll_period_warm_boot, 1:0, scratch13, 31:30); +// s32(emc_bct_spare13, scratch45); +// s32(emc_bct_spare12, scratch46); +// s32(emc_bct_spare7, scratch47); +// s32(emc_bct_spare6, scratch48); +// s32(emc_bct_spare5, scratch50); +// s32(emc_bct_spare4, scratch51); +// s32(emc_bct_spare3, scratch56); +// s32(emc_bct_spare2, scratch57); +// s32(emc_bct_spare1, scratch58); +// s32(emc_bct_spare0, scratch59); +// s32(emc_bct_spare9, scratch60); +// s32(emc_bct_spare8, scratch61); +// s32(boot_rom_patch_data, scratch62); +// s32(boot_rom_patch_control, scratch63); +// s(mc_clken_override_allwarm_boot, 0:0, scratch65, 31:31); +// pmc->scratch66 = pmc->scratch66 & 0x1FFFFFFF | ((u8)(sdram->emc_extra_refresh_num) << 29); +// pmc->scratch72 = pmc->scratch72 & 0x8FFFFFFF | ((u16)(sdram->pmc_io_dpd3_req_wait) << 28) & 0x70000000; +// pmc->scratch72 = ((2 * pmc->scratch72) >> 1) | ((u16)(sdram->emc_clken_override_allwarm_boot) << 31); +// pmc->scratch73 = pmc->scratch73 & 0x8FFFFFFF | ((u8)(sdram->memory_type) << 28) & 0x70000000; +// pmc->scratch73 = ((2 * pmc->scratch73) >> 1) | (sdram->emc_mrs_warm_boot_enable << 31); +// pmc->scratch74 = pmc->scratch74 & 0x8FFFFFFF | (sdram->pmc_io_dpd4_req_wait << 28) & 0x70000000; +// pmc->scratch74 = ((2 * pmc->scratch74) >> 1) | (sdram->clear_clock2_mc1 << 31); +// pmc->scratch75 = pmc->scratch75 & 0xEFFFFFFF | (sdram->emc_warm_boot_extramode_reg_write_enable << 28) & 0x10000000; +// pmc->scratch75 = pmc->scratch75 & 0xDFFFFFFF | (sdram->clk_rst_pllm_misc20_override_enable << 29) & 0x20000000; +// pmc->scratch75 = pmc->scratch75 & 0xBFFFFFFF | ((u16)(sdram->emc_dbg_write_mux) << 30) & 0x40000000; +// pmc->scratch75 = ((2 * pmc->scratch75) >> 1) | ((u16)(sdram->ahb_arbitration_xbar_ctrl_meminit_done) << 31); +// pmc->scratch90 = pmc->scratch90 & 0xFFFFFF | (sdram->emc_timing_control_wait << 24); +// pmc->scratch91 = pmc->scratch91 & 0xFFFFFF | (sdram->emc_zcal_warm_boot_wait << 24); +// pmc->scratch92 = pmc->scratch92 & 0xFFFFFF | (sdram->warm_boot_wait << 24); +// pmc->scratch93 = pmc->scratch93 & 0xFFFFFF | ((u16)(sdram->emc_pin_program_wait) << 24); +// pmc->scratch114 = pmc->scratch114 & 0x3FFFFF | ((u16)(sdram->emc_auto_cal_wait) << 22); +// pmc->scratch215 = (u16)pmc->scratch215 | ((u16)(sdram->swizzle_rank_byte_encode) << 16); +// pmc->scratch216 = (2 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 30) | ((4 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 29) | ((8 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 28) | ((16 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 27) | ((32 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 26) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 6 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF; +// s(emc_mrw_lpddr2zcal_warm_boot, 23:16, scratch5, 7:0); +// s(emc_mrw_lpddr2zcal_warm_boot, 7:0, scratch5, 15:8); +// s(emc_warm_boot_mrw_extra, 23:16, scratch5, 23:16); +// s(emc_warm_boot_mrw_extra, 7:0, scratch5, 31:24); +// s(emc_mrw_lpddr2zcal_warm_boot, 31:30, scratch6, 1:0); +// s(emc_warm_boot_mrw_extra, 31:30, scratch6, 3:2); +// s(emc_mrw_lpddr2zcal_warm_boot, 27:26, scratch6, 5:4); +// s(emc_warm_boot_mrw_extra, 27:26, scratch6, 7:6); +// s(EmcMrw6, 27:0, scratch8, 27:0); +// s(EmcMrw6, 31:30, scratch8, 29:28); +// s(EmcMrw8, 27:0, scratch9, 27:0); +// s(EmcMrw8, 31:30, scratch9, 29:28); +// s(EmcMrw9, 27:0, scratch10, 27:0); +// s(EmcMrw9, 31:30, scratch10, 29:28); +// s(EmcMrw10, 27:0, scratch11, 27:0); +// s(EmcMrw10, 31:30, scratch11, 29:28); +// s(EmcMrw12, 27:0, scratch12, 27:0); +// s(EmcMrw12, 31:30, scratch12, 29:28); +// s(EmcMrw13, 27:0, scratch13, 27:0); +// s(EmcMrw13, 31:30, scratch13, 29:28); +// s(EmcMrw14, 27:0, scratch14, 27:0); +// s(EmcMrw14, 31:30, scratch14, 29:28); +// s(EmcMrw1, 7:0, scratch15, 7:0); +// s(EmcMrw1, 23:16, scratch15, 15:8); +// s(EmcMrw1, 27:26, scratch15, 17:16); +// s(EmcMrw1, 31:30, scratch15, 19:18); +// s(emc_warm_boot_mrw_extra, 7:0, scratch16, 7:0); +// s(emc_warm_boot_mrw_extra, 23:16, scratch16, 15:8); +// s(emc_warm_boot_mrw_extra, 27:26, scratch16, 17:16); +// s(emc_warm_boot_mrw_extra, 31:30, scratch16, 19:18); +// s(emc_mrw2, 7:0, scratch17, 7:0); +// s(emc_mrw2, 23:16, scratch17, 15:8); +// s(emc_mrw2, 27:26, scratch17, 17:16); +// s(emc_mrw2, 31:30, scratch17, 19:18); +// pmc->scratch18 = (sdram->emc_mrw3 >> 30 << 18) | ((16 * sdram->emc_mrw3 >> 31 << 17) | ((32 * sdram->emc_mrw3 >> 31 << 16) | ((sdram->emc_mrw3 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw3 | (pmc->scratch18 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; +// pmc->scratch19 = (sdram->emc_mrw4 >> 30 << 18) | ((16 * sdram->emc_mrw4 >> 31 << 17) | ((32 * sdram->emc_mrw4 >> 31 << 16) | ((sdram->emc_mrw4 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw4 | (pmc->scratch19 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; +// s32(emc_cmd_mapping_byte, secure_scratch8); +// s32(emc_pmacro_brick_mapping0, secure_scratch9); +// s32(emc_pmacro_brick_mapping1, secure_scratch10); +// s32(emc_pmacro_brick_mapping2, secure_scratch11); +// s32(mc_video_protect_gpu_override0, secure_scratch12); +// pmc->secure_scratch13 = ((u16)(sdram->emc_adr_cfg) << 31) | (2 * ((((u16)(sdram->mc_untranslated_region_check) << 22) >> 31 << 30) | ((((u16)(sdram->mc_untranslated_region_check) << 23) >> 31 << 29) | (((u16)(sdram->mc_untranslated_region_check) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd0_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_0 & 0x7F | (pmc->secure_scratch13 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch14 = (sdram->mc_video_protect_write_access << 30 >> 31 << 31) | (2 * ((sdram->mc_video_protect_write_access << 30) | ((sdram->mc_video_protect_bom_adr_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd0_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_1 & 0x7F | (pmc->secure_scratch14 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch15 = ((u16)(sdram->mc_mts_carveout_adr_hi) << 30) | (4 * ((sdram->mc_sec_carveout_adr_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_0 & 0x7F | (pmc->secure_scratch15 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); +// pmc->secure_scratch16 = (sdram->mc_generalized_carveout3_bom_hi << 30) | (4 * ((sdram->mc_generalized_carveout5_bom_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_1 & 0x7F | (pmc->secure_scratch16 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); +// pmc->secure_scratch17 = ((u16)(sdram->mc_generalized_carveout4_bom_hi) << 30) | (4 * (((u16)(sdram->mc_generalized_carveout2_bom_hi) << 28) | ((2 * sdram->emc_cmd_mapping_cmd2_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_0 & 0x7F | (pmc->secure_scratch17 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); +// pmc->secure_scratch18 = (sdram->emc_fbio_cfg8 << 16 >> 31 << 31) | (2 * (((u16)(sdram->emc_fbio_spare) << 30 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd2_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_1 & 0x7F | (pmc->secure_scratch18 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch19 = (sdram->mc_video_protect_vpr_override << 31) | (2 * (((u16)(sdram->mc_mts_carveout_reg_ctrl) << 30) | ((sdram->mc_sec_carveout_protect_write_access << 31 >> 2) | (((u16)(sdram->mc_emem_adr_cfg) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd3_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_0 & 0x7F | (pmc->secure_scratch19 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch20 = (sdram->mc_generalized_carveout2_cfg0 << 25 >> 28 << 28) | ((2 * sdram->emc_cmd_mapping_cmd3_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_1 & 0x7F | (pmc->secure_scratch20 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; +// pmc->secure_scratch39 = (sdram->mc_video_protect_vpr_override << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 21 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout4_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout4_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout4_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout4_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout4_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout4_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout4_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout4_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout4_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout4_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout4_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout4_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout4_cfg0 & 1 | 2 * (pmc->secure_scratch39 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); +// pmc->secure_scratch40 = (sdram->mc_video_protect_vpr_override << 29 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 14 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout5_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout5_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout5_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout5_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout5_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout5_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout5_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout5_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout5_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout5_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout5_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout5_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout5_cfg0 & 1 | 2 * (pmc->secure_scratch40 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); +// pmc->secure_scratch41 = (sdram->mc_generalized_carveout2_cfg0 << 18 >> 29 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 10 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd0_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd0_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_2 & 0x7F | (pmc->secure_scratch41 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; +// pmc->secure_scratch42 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 25 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd1_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd1_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_2 & 0x7F | (pmc->secure_scratch42 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; +// pmc->secure_scratch43 = ((u16)(sdram->mc_generalized_carveout3_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 21 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd2_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd2_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_2 & 0x7F | (pmc->secure_scratch43 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; +// pmc->secure_scratch44 = (sdram->mc_video_protect_vpr_override << 24 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 25 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override << 28 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 14 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd3_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd3_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_2 & 0x7F | (pmc->secure_scratch44 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// s(mc_emem_adr_cfg_channel_mask, 31:9, secure_scratch45, 22:0); +// s(mc_emem_adr_cfg_dev0, 2:0, secure_scratch45, 25:23); +// s(mc_emem_adr_cfg_dev0, 9:8, secure_scratch45, 27:26); +// s(mc_emem_adr_cfg_dev0, 19:16, secure_scratch45, 31:28); +// pmc->secure_scratch46 = (sdram->mc_video_protect_vpr_override << 23 >> 31 << 31) | (2 * ((sdram->mc_emem_adr_cfg_dev1 << 12 >> 28 << 27) | ((sdram->mc_emem_adr_cfg_dev1 << 22 >> 30 << 25) | ((sdram->mc_emem_adr_cfg_dev1 << 22) & 0x1FFFFFF | ((sdram->mc_emem_adr_cfg_bank_mask0 >> 10) | (pmc->secure_scratch46 >> 22 << 22)) & 0xFE3FFFFF) & 0xF9FFFFFF) & 0x87FFFFFF) >> 1); +// pmc->secure_scratch47 = (sdram->mc_video_protect_vpr_override << 20 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 22 >> 31 << 30) | (((u8)(sdram->mc_generalized_carveout3_cfg0) << 25 >> 28 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 10 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask1 >> 10) | (pmc->secure_scratch47 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch48 = (sdram->mc_video_protect_vpr_override << 16 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 17 >> 31 << 30) | ((sdram->mc_generalized_carveout3_cfg0 << 14 >> 28 << 26) | ((sdram->mc_generalized_carveout3_cfg0 << 21 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask2 >> 10) | (pmc->secure_scratch48 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch49 = (sdram->mc_video_protect_vpr_override << 14 >> 31 << 31) | (2 * ((sdram->mc_emem_cfg >> 31 << 30) | ((sdram->mc_emem_cfg << 18 >> 2) | (sdram->mc_video_protect_gpu_override1 & 0xFFFF | (pmc->secure_scratch49 >> 16 << 16)) & 0xC000FFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch50 = (sdram->mc_video_protect_vpr_override << 12 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 13 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom >> 17 << 15) | ((sdram->mc_generalized_carveout3_bom >> 17) | (pmc->secure_scratch50 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch51 = (sdram->mc_video_protect_vpr_override << 10 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 11 >> 31 << 30) | ((sdram->mc_generalized_carveout2_bom >> 17 << 15) | ((sdram->mc_generalized_carveout4_bom >> 17) | (pmc->secure_scratch51 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch52 = (sdram->mc_video_protect_vpr_override << 9 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout3_cfg0 << 10 >> 28 << 27) | ((sdram->mc_video_protect_bom >> 20 << 15) | ((sdram->mc_generalized_carveout5_bom >> 17) | (pmc->secure_scratch52 >> 15 << 15)) & 0xF8007FFF) & 0x87FFFFFF) >> 1); +// pmc->secure_scratch53 = (sdram->mc_video_protect_vpr_override1 << 27 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 30 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 31 >> 2) | ((sdram->mc_video_protect_vpr_override >> 31 << 28) | ((2 * sdram->mc_video_protect_vpr_override >> 31 << 27) | ((4 * sdram->mc_video_protect_vpr_override >> 31 << 26) | ((32 * sdram->mc_video_protect_vpr_override >> 31 << 25) | ((sdram->mc_video_protect_vpr_override << 8 >> 31 << 24) | ((sdram->mc_sec_carveout_bom >> 20 << 12) | (sdram->mc_video_protect_size_mb & 0xFFF | (pmc->secure_scratch53 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch54 = (sdram->mc_video_protect_vpr_override1 << 19 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 20 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 21 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 22 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 23 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 24 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 25 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 26 >> 31 << 24) | ((sdram->mc_mts_carveout_bom >> 20 << 12) | (sdram->mc_sec_carveout_size_mb & 0xFFF | (pmc->secure_scratch54 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch55 = (sdram->mc_generalized_carveout2_cfg0 << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 30) | ((32 * sdram->mc_video_protect_vpr_override1 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 6 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 15 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 16 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 17 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 18 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout4_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_mts_carveout_size_mb & 0xFFF | (pmc->secure_scratch55 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch56 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 30 >> 31 << 31) | (2 * (((u16)(sdram->mc_generalized_carveout1_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout2_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout2_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout2_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout2_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout2_cfg0 << 29 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout2_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout3_size_128kb & 0xFFF | (pmc->secure_scratch56 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); +// pmc->secure_scratch57 = ((u8)(sdram->mc_generalized_carveout3_cfg0) << 30 >> 31 << 31) | (2 * (((u8)(sdram->mc_generalized_carveout3_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout1_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout1_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout1_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout1_cfg0 << 29 >> 31 << 24) | ((sdram->mc_generalized_carveout5_size_128kb << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout1_size_128kb & 0xFFF | (pmc->secure_scratch57 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + +// s32(mc_generalized_carveout1_access0, secure_scratch59); +// s32(mc_generalized_carveout1_access1, secure_scratch60); +// s32(mc_generalized_carveout1_access2, secure_scratch61); +// s32(mc_generalized_carveout1_access3, secure_scratch62); +// s32(mc_generalized_carveout1_access4, secure_scratch63); +// s32(mc_generalized_carveout2_access0, secure_scratch64); +// s32(mc_generalized_carveout2_access1, secure_scratch65); +// s32(mc_generalized_carveout2_access2, secure_scratch66); +// s32(mc_generalized_carveout2_access3, secure_scratch67); +// s32(mc_generalized_carveout2_access4, secure_scratch68); +// s32(mc_generalized_carveout3_access0, secure_scratch69); +// s32(mc_generalized_carveout3_access1, secure_scratch70); +// s32(mc_generalized_carveout3_access2, secure_scratch71); +// s32(mc_generalized_carveout3_access3, secure_scratch72); +// s32(mc_generalized_carveout3_access4, secure_scratch73); +// s32(mc_generalized_carveout4_access0, secure_scratch74); +// s32(mc_generalized_carveout4_access1, secure_scratch75); +// s32(mc_generalized_carveout4_access2, secure_scratch76); +// s32(mc_generalized_carveout4_access3, secure_scratch77); +// s32(mc_generalized_carveout4_access4, secure_scratch78); +// s32(mc_generalized_carveout5_access0, secure_scratch79); +// s32(mc_generalized_carveout5_access1, secure_scratch80); +// s32(mc_generalized_carveout5_access2, secure_scratch81); +// s32(mc_generalized_carveout5_access3, secure_scratch82); +// s32(mc_generalized_carveout1_force_internal_access0, secure_scratch84); +// s32(mc_generalized_carveout1_force_internal_access1, secure_scratch85); +// s32(mc_generalized_carveout1_force_internal_access2, secure_scratch86); +// s32(mc_generalized_carveout1_force_internal_access3, secure_scratch87); +// s32(mc_generalized_carveout1_force_internal_access4, secure_scratch88); +// s32(mc_generalized_carveout2_force_internal_access0, secure_scratch89); +// s32(mc_generalized_carveout2_force_internal_access1, secure_scratch90); +// s32(mc_generalized_carveout2_force_internal_access2, secure_scratch91); +// s32(mc_generalized_carveout2_force_internal_access3, secure_scratch92); +// s32(mc_generalized_carveout2_force_internal_access4, secure_scratch93); +// s32(mc_generalized_carveout3_force_internal_access0, secure_scratch94); +// s32(mc_generalized_carveout3_force_internal_access1, secure_scratch95); +// s32(mc_generalized_carveout3_force_internal_access2, secure_scratch96); +// s32(mc_generalized_carveout3_force_internal_access3, secure_scratch97); +// s32(mc_generalized_carveout3_force_internal_access4, secure_scratch98); +// s32(mc_generalized_carveout4_force_internal_access0, secure_scratch99); +// s32(mc_generalized_carveout4_force_internal_access1, secure_scratch100); +// s32(mc_generalized_carveout4_force_internal_access2, secure_scratch101); +// s32(mc_generalized_carveout4_force_internal_access3, secure_scratch102); +// s32(mc_generalized_carveout4_force_internal_access4, secure_scratch103); +// s32(mc_generalized_carveout5_force_internal_access0, secure_scratch104); +// s32(mc_generalized_carveout5_force_internal_access1, secure_scratch105); +// s32(mc_generalized_carveout5_force_internal_access2, secure_scratch106); +// s32(mc_generalized_carveout5_force_internal_access3, secure_scratch107); + +// pmc->secure_scratch58 = 32 * (32 * sdram->mc_generalized_carveout3_cfg0 >> 31) | (16 * (sdram->mc_generalized_carveout3_cfg0 << 6 >> 31) | (8 * (sdram->mc_generalized_carveout3_cfg0 << 7 >> 31) | (4 * (sdram->mc_generalized_carveout3_cfg0 << 8 >> 31) | (2 * (sdram->mc_generalized_carveout3_cfg0 << 9 >> 31) | ((sdram->mc_generalized_carveout3_cfg0 << 29 >> 31) | 2 * (pmc->secure_scratch58 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; + +// c32(0, scratch2); +// s(pllm_input_divider, 7:0, scratch2, 7:0); +// s(pllm_feedback_divider, 7:0, scratch2, 15:8); +// s(pllm_post_divider, 4:0, scratch2, 20:16); +// s(pllm_kvco, 0:0, scratch2, 17:17); +// s(pllm_kcp, 1:0, scratch2, 19:18); + +// c32(0, scratch35); +// s(pllm_setup_control, 15:0, scratch35, 15:0); + +// c32(0, scratch3); +// s(pllm_input_divider, 7:0, scratch3, 7:0); +// c(0x3e, scratch3, 15:8); +// c(0, scratch3, 20:16); +// s(pllm_kvco, 0:0, scratch3, 21:21); +// s(pllm_kcp, 1:0, scratch3, 23:22); + +// c32(0, scratch36); +// s(PllMSetupControl, 23:0, scratch36, 23:0); + +// c32(0, scratch4); +// s(pllm_stable_time, 9:0, scratch4, 9:0); // s32(pllm_stable_time, scratch4);, s(pllm_stable_time, 31:0, scratch4, 31:10); +// s(pllm_stable_time, 31:0, scratch4, 31:10); +// } + +#pragma GCC diagnostic pop + +void sdram_lp0_save_params(const void *params) +{ + // u32 chip_id = (APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF; + + // if (chip_id != GP_HIDREV_MAJOR_T210B01) + _sdram_lp0_save_params_t210(params); + // else + // _sdram_lp0_save_params_t210b01(params); +} diff --git a/bdk/mem/sdram_lp0_param_t210.h b/bdk/mem/sdram_lp0_param_t210.h index 1422ed3..09e960e 100644 --- a/bdk/mem/sdram_lp0_param_t210.h +++ b/bdk/mem/sdram_lp0_param_t210.h @@ -20,8 +20,8 @@ * directly converting BCT config files (*.cfg) into C structure. */ -#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ -#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ +#ifndef __TEGRA210_SDRAM_PARAM_H__ +#define __TEGRA210_SDRAM_PARAM_H__ #include @@ -57,7 +57,7 @@ enum /** * Defines the SDRAM parameter structure */ -struct sdram_params +struct sdram_params_t210 { /* Specifies the type of memory device */ diff --git a/bdk/mem/sdram_lp0_param_t210b01.h b/bdk/mem/sdram_lp0_param_t210b01.h new file mode 100644 index 0000000..f987a1e --- /dev/null +++ b/bdk/mem/sdram_lp0_param_t210b01.h @@ -0,0 +1,990 @@ +/* + * Copyright (c) 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. + */ + +#ifndef __TEGRA210B01_SDRAM_PARAM_H__ +#define __TEGRA210B01_SDRAM_PARAM_H__ + +#include + +struct sdram_params_t210b01 +{ + /* Specifies the type of memory device */ + u32 memory_type; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 pllm_input_divider; + /* Specifies the N value for PllM */ + u32 pllm_feedback_divider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 pllm_stable_time; + /* Specifies misc. control bits */ + u32 pllm_setup_control; + /* Specifies the P value for PLLM */ + u32 pllm_post_divider; + /* Specifies value for Charge Pump Gain Control */ + u32 pllm_kcp; + /* Specifies VCO gain */ + u32 pllm_kvco; + /* Spare BCT param */ + u32 emc_bct_spare0; + /* Spare BCT param */ + u32 emc_bct_spare1; + /* Spare BCT param */ + u32 emc_bct_spare2; + /* Spare BCT param */ + u32 emc_bct_spare3; + /* Spare BCT param */ + u32 emc_bct_spare4; + /* Spare BCT param */ + u32 emc_bct_spare5; + /* Spare BCT param */ + u32 emc_bct_spare6; + /* Spare BCT param */ + u32 emc_bct_spare7; + /* Spare BCT param */ + u32 emc_bct_spare8; + /* Spare BCT param */ + u32 emc_bct_spare9; + /* Spare BCT param */ + u32 emc_bct_spare10; + /* Spare BCT param */ + u32 emc_bct_spare11; + /* Spare BCT param */ + u32 emc_bct_spare12; + /* Spare BCT param */ + u32 emc_bct_spare13; + /* Spare BCT param */ + u32 emc_bct_spare_secure0; + /* Spare BCT param */ + u32 emc_bct_spare_secure1; + /* Spare BCT param */ + u32 emc_bct_spare_secure2; + /* Spare BCT param */ + u32 emc_bct_spare_secure3; + /* Spare BCT param */ + u32 emc_bct_spare_secure4; + /* Spare BCT param */ + u32 emc_bct_spare_secure5; + /* Spare BCT param */ + u32 emc_bct_spare_secure6; + /* Spare BCT param */ + u32 emc_bct_spare_secure7; + /* Spare BCT param */ + u32 emc_bct_spare_secure8; + /* Spare BCT param */ + u32 emc_bct_spare_secure9; + /* Spare BCT param */ + u32 emc_bct_spare_secure10; + /* Spare BCT param */ + u32 emc_bct_spare_secure11; + /* Spare BCT param */ + u32 emc_bct_spare_secure12; + /* Spare BCT param */ + u32 emc_bct_spare_secure13; + /* Spare BCT param */ + u32 emc_bct_spare_secure14; + /* Spare BCT param */ + u32 emc_bct_spare_secure15; + /* Spare BCT param */ + u32 emc_bct_spare_secure16; + /* Spare BCT param */ + u32 emc_bct_spare_secure17; + /* Spare BCT param */ + u32 emc_bct_spare_secure18; + /* Spare BCT param */ + u32 emc_bct_spare_secure19; + /* Spare BCT param */ + u32 emc_bct_spare_secure20; + /* Spare BCT param */ + u32 emc_bct_spare_secure21; + /* Spare BCT param */ + u32 emc_bct_spare_secure22; + /* Spare BCT param */ + u32 emc_bct_spare_secure23; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 emc_clock_source; + u32 emc_clock_source_dll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override; + /* enables override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override_enable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 clear_clock2_mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 emc_auto_cal_interval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 emc_auto_cal_config; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 emc_auto_cal_config2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 emc_auto_cal_config3; + u32 emc_auto_cal_config4; + u32 emc_auto_cal_config5; + u32 emc_auto_cal_config6; + u32 emc_auto_cal_config7; + u32 emc_auto_cal_config8; + u32 emc_auto_cal_config9; + + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 emc_auto_cal_vref_sel0; + u32 emc_auto_cal_vref_sel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 emc_auto_cal_channel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 emc_pmacro_auto_cal_cfg0; + u32 emc_pmacro_auto_cal_cfg1; + u32 emc_pmacro_auto_cal_cfg2; + + u32 emc_pmacro_rx_term; + u32 emc_pmacro_dq_tx_drive; + u32 emc_pmacro_ca_tx_drive; + u32 emc_pmacro_cmd_tx_drive; + u32 emc_pmacro_auto_cal_common; + u32 emc_pmacro_zcrtl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 emc_auto_cal_wait; + + u32 emc_xm2_comp_pad_ctrl; + u32 emc_xm2_comp_pad_ctrl2; + u32 emc_xm2_comp_pad_ctrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 emc_adr_cfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 emc_pin_program_wait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 emc_pin_extra_wait; + + u32 emc_pin_gpio_enable; + u32 emc_pin_gpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 emc_timing_control_wait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 emc_rc; + /* Specifies the value for EMC_RFC */ + u32 emc_rfc; + + u32 emc_rfc_pb; + u32 emc_ref_ctrl2; + + /* Specifies the value for EMC_RFC_SLR */ + u32 emc_rfc_slr; + /* Specifies the value for EMC_RAS */ + u32 emc_ras; + /* Specifies the value for EMC_RP */ + u32 emc_rp; + /* Specifies the value for EMC_R2R */ + u32 emc_r2r; + /* Specifies the value for EMC_W2W */ + u32 emc_w2w; + /* Specifies the value for EMC_R2W */ + u32 emc_r2w; + /* Specifies the value for EMC_W2R */ + u32 emc_w2r; + /* Specifies the value for EMC_R2P */ + u32 emc_r2p; + /* Specifies the value for EMC_W2P */ + u32 emc_w2p; + /* Specifies the value for EMC_RD_RCD */ + + u32 emc_tppd; + u32 emc_trtm; + u32 emc_twtm; + u32 emc_tratm; + u32 emc_twatm; + u32 emc_tr2ref; + u32 emc_ccdmw; + + u32 emc_rd_rcd; + /* Specifies the value for EMC_WR_RCD */ + u32 emc_wr_rcd; + /* Specifies the value for EMC_RRD */ + u32 emc_rrd; + /* Specifies the value for EMC_REXT */ + u32 emc_rext; + /* Specifies the value for EMC_WEXT */ + u32 emc_wext; + /* Specifies the value for EMC_WDV */ + u32 emc_wdv; + + u32 emc_wdv_chk; + u32 emc_wsv; + u32 emc_wev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 emc_wdv_mask; + + u32 emc_ws_duration; + u32 emc_we_duration; + + /* Specifies the value for EMC_QUSE */ + u32 emc_quse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 emc_quse_width; + /* Specifies the value for EMC_IBDLY */ + u32 emc_ibdly; + + u32 emc_obdly; + + /* Specifies the value for EMC_EINPUT */ + u32 emc_einput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 emc_einput_duration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 emc_puterm_extra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 emc_puterm_width; + + u32 emc_qrst; + u32 emc_qsafe; + u32 emc_rdv; + u32 emc_rdv_mask; + + u32 emc_rdv_early; + u32 emc_rdv_early_mask; + + /* Specifies the value for EMC_QPOP */ + u32 emc_qpop; + + /* Specifies the value for EMC_REFRESH */ + u32 emc_refresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 emc_burst_refresh_num; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 emc_prerefresh_req_cnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 emc_pdex2wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 emc_pdex2rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 emc_pchg2pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 emc_act2pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 emc_ar2pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 emc_rw2pden; + + u32 emc_cke2pden; + u32 emc_pdex2che; + u32 emc_pdex2mrr; + + /* Specifies the value for EMC_TXSR */ + u32 emc_txsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 emc_txsr_dll; + /* Specifies the value for EMC_TCKE */ + u32 emc_tcke; + /* Specifies the value for EMC_TCKESR */ + u32 emc_tckesr; + /* Specifies the value for EMC_TPD */ + u32 emc_tpd; + /* Specifies the value for EMC_TFAW */ + u32 emc_tfaw; + /* Specifies the value for EMC_TRPAB */ + u32 emc_trpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 emc_tclkstable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 emc_tclkstop; + /* Specifies the value for EMC_TREFBW */ + u32 emc_trefbw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 emc_fbio_cfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 emc_fbio_cfg7; + u32 emc_fbio_cfg8; + + /* Command mapping for CMD brick 0 */ + u32 emc_cmd_mapping_cmd0_0; + u32 emc_cmd_mapping_cmd0_1; + u32 emc_cmd_mapping_cmd0_2; + u32 emc_cmd_mapping_cmd1_0; + u32 emc_cmd_mapping_cmd1_1; + u32 emc_cmd_mapping_cmd1_2; + u32 emc_cmd_mapping_cmd2_0; + u32 emc_cmd_mapping_cmd2_1; + u32 emc_cmd_mapping_cmd2_2; + u32 emc_cmd_mapping_cmd3_0; + u32 emc_cmd_mapping_cmd3_1; + u32 emc_cmd_mapping_cmd3_2; + u32 emc_cmd_mapping_byte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 emc_fbio_spare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 emc_cfg_rsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 emc_mrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 emc_emrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 emc_emrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 emc_emrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 emc_mrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 emc_mrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 emc_mrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 emc_mrw4; + + /* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */ + u32 emc_mrw6; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw8; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw9; + /* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */ + u32 emc_mrw10; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw12; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw13; + /* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */ + u32 emc_mrw14; + + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 emc_mrw_extra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 emc_warm_boot_mrw_extra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 emc_warm_boot_extramode_reg_write_enable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 emc_extramode_reg_write_enable; + + /* Specifies the EMC_MRW reset command value */ + u32 emc_mrw_reset_command; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 emc_mrw_reset_ninit_wait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 emc_mrs_wait_cnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 emc_mrs_wait_cnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 emc_cfg; + /* Specifies the value for EMC_CFG_2 */ + u32 emc_cfg2; + /* Specifies the pipe bypass controls */ + u32 emc_cfg_pipe; + + u32 emc_cfg_pipe_clk; + u32 emc_fdpd_ctrl_cmd_no_ramp; + u32 emc_cfg_update; + + /* Specifies the value for EMC_DBG */ + u32 emc_dbg; + + u32 emc_dbg_write_mux; + + /* Specifies the value for EMC_CMDQ */ + u32 emc_cmd_q; + /* Specifies the value for EMC_MC2EMCQ */ + u32 emc_mc2emc_q; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 emc_dyn_self_ref_control; + + /* Specifies the value for MEM_INIT_DONE */ + u32 ahb_arbitration_xbar_ctrl_meminit_done; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 emc_cfg_dig_dll; + u32 emc_cfg_dig_dll_1; + + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 emc_cfg_dig_dll_period; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 emc_dev_select; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 emc_sel_dpd_ctrl; + + /* Pads trimmer delays */ + u32 emc_fdpd_ctrl_dq; + u32 emc_fdpd_ctrl_cmd; + u32 emc_pmacro_ib_vref_dq_0; + u32 emc_pmacro_ib_vref_dq_1; + u32 emc_pmacro_ib_vref_dqs_0; + u32 emc_pmacro_ib_vref_dqs_1; + u32 emc_pmacro_ib_rxrt; + u32 emc_cfg_pipe1; + u32 emc_cfg_pipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 emc_pmacro_quse_ddll_rank0_0; + u32 emc_pmacro_quse_ddll_rank0_1; + u32 emc_pmacro_quse_ddll_rank0_2; + u32 emc_pmacro_quse_ddll_rank0_3; + u32 emc_pmacro_quse_ddll_rank0_4; + u32 emc_pmacro_quse_ddll_rank0_5; + u32 emc_pmacro_quse_ddll_rank1_0; + u32 emc_pmacro_quse_ddll_rank1_1; + u32 emc_pmacro_quse_ddll_rank1_2; + u32 emc_pmacro_quse_ddll_rank1_3; + u32 emc_pmacro_quse_ddll_rank1_4; + u32 emc_pmacro_quse_ddll_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dq_rank0_0; + u32 emc_pmacro_ob_ddll_long_dq_rank0_1; + u32 emc_pmacro_ob_ddll_long_dq_rank0_2; + u32 emc_pmacro_ob_ddll_long_dq_rank0_3; + u32 emc_pmacro_ob_ddll_long_dq_rank0_4; + u32 emc_pmacro_ob_ddll_long_dq_rank0_5; + u32 emc_pmacro_ob_ddll_long_dq_rank1_0; + u32 emc_pmacro_ob_ddll_long_dq_rank1_1; + u32 emc_pmacro_ob_ddll_long_dq_rank1_2; + u32 emc_pmacro_ob_ddll_long_dq_rank1_3; + u32 emc_pmacro_ob_ddll_long_dq_rank1_4; + u32 emc_pmacro_ob_ddll_long_dq_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_5; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_5; + + u32 emc_pmacro_ib_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_3; + + u32 emc_pmacro_ddll_long_cmd_0; + u32 emc_pmacro_ddll_long_cmd_1; + u32 emc_pmacro_ddll_long_cmd_2; + u32 emc_pmacro_ddll_long_cmd_3; + u32 emc_pmacro_ddll_long_cmd_4; + u32 emc_pmacro_ddll_short_cmd_0; + u32 emc_pmacro_ddll_short_cmd_1; + u32 emc_pmacro_ddll_short_cmd_2; + + u32 emc_pmacro_ddll_periodic_offset; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 warm_boot_wait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 emc_odt_write; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 emc_zcal_interval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 emc_zcal_wait_cnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 emc_zcal_mrw_cmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 emc_mrs_reset_dll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 emc_zcal_init_dev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 emc_zcal_init_dev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 emc_zcal_init_wait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 emc_zcal_warm_cold_boot_enables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 emc_mrw_lpddr2zcal_warm_boot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 emc_zqcal_ddr3_warm_boot; + + u32 emc_zqcal_lpddr4_warm_boot; + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 emc_zcal_warm_boot_wait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 emc_mrs_warm_boot_enable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 emc_mrs_reset_dll_wait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 emc_mrs_extra; + /* Specifies the extra MRS command at warm boot */ + u32 emc_warm_boot_mrs_extra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 emc_emrs_ddr2_dll_enable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 emc_mrs_ddr2_dll_reset; + /* Specifies the EMRS command to set OCD calibration */ + u32 emc_emrs_ddr2_ocd_calib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 emc_ddr2_wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 emc_clken_override; + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 emc_extra_refresh_num; + /* Specifies the master override for all EMC clocks */ + u32 emc_clken_override_allwarm_boot; + /* Specifies the master override for all MC clocks */ + u32 mc_clken_override_allwarm_boot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 emc_cfg_dig_dll_period_warm_boot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 pmc_vddp_sel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 pmc_vddp_sel_wait; + /* Specifies the value for PMC_DDR_CFG */ + u32 pmc_ddr_cfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req_wait; + + u32 pmc_io_dpd4_req_wait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 pmc_reg_short; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 pmc_no_io_power; + + u32 pmc_ddr_ctrl_wait; + u32 pmc_ddr_ctrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 emc_acpd_control; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 emc_swizzle_rank0_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 emc_swizzle_rank0_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 emc_swizzle_rank0_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 emc_swizzle_rank0_byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 emc_swizzle_rank1_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 emc_swizzle_rank1_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 emc_swizzle_rank1_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 emc_swizzle_rank1_byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 emc_txdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 emc_data_brlshft0; + u32 emc_data_brlshft1; + + u32 emc_dqs_brlshft0; + u32 emc_dqs_brlshft1; + + u32 emc_cmd_brlshft0; + u32 emc_cmd_brlshft1; + u32 emc_cmd_brlshft2; + u32 emc_cmd_brlshft3; + + u32 emc_quse_brlshft0; + u32 emc_quse_brlshft1; + u32 emc_quse_brlshft2; + u32 emc_quse_brlshft3; + + u32 emc_dll_cfg0; + u32 emc_dll_cfg1; + + u32 emc_pmc_scratch1; + u32 emc_pmc_scratch2; + u32 emc_pmc_scratch3; + + u32 emc_pmacro_pad_cfg_ctrl; + + u32 emc_pmacro_vttgen_ctrl0; + u32 emc_pmacro_vttgen_ctrl1; + u32 emc_pmacro_vttgen_ctrl2; + u32 emc_pmacro_dsr_vttgen_ctrl0; + u32 emc_pmacro_brick_ctrl_rfu1; + u32 emc_pmacro_cmd_brick_ctrl_fdpd; + u32 emc_pmacro_brick_ctrl_rfu2; + u32 emc_pmacro_data_brick_ctrl_fdpd; + u32 emc_pmacro_bg_bias_ctrl0; + u32 emc_pmacro_data_pad_rx_ctrl; + u32 emc_pmacro_cmd_pad_rx_ctrl; + u32 emc_pmacro_data_rx_term_mode; + u32 emc_pmacro_cmd_rx_term_mode; + u32 emc_pmacro_data_pad_tx_ctrl; + u32 emc_pmacro_cmd_pad_tx_ctrl; + u32 emc_cfg3; + + u32 emc_pmacro_tx_pwrd0; + u32 emc_pmacro_tx_pwrd1; + u32 emc_pmacro_tx_pwrd2; + u32 emc_pmacro_tx_pwrd3; + u32 emc_pmacro_tx_pwrd4; + u32 emc_pmacro_tx_pwrd5; + + u32 emc_config_sample_delay; + + u32 emc_pmacro_brick_mapping0; + u32 emc_pmacro_brick_mapping1; + u32 emc_pmacro_brick_mapping2; + + u32 emc_pmacro_tx_sel_clk_src0; + u32 emc_pmacro_tx_sel_clk_src1; + u32 emc_pmacro_tx_sel_clk_src2; + u32 emc_pmacro_tx_sel_clk_src3; + u32 emc_pmacro_tx_sel_clk_src4; + u32 emc_pmacro_tx_sel_clk_src5; + + u32 emc_pmacro_perbit_fgcg_ctrl0; + u32 emc_pmacro_perbit_fgcg_ctrl1; + u32 emc_pmacro_perbit_fgcg_ctrl2; + u32 emc_pmacro_perbit_fgcg_ctrl3; + u32 emc_pmacro_perbit_fgcg_ctrl4; + u32 emc_pmacro_perbit_fgcg_ctrl5; + u32 emc_pmacro_perbit_rfu_ctrl0; + u32 emc_pmacro_perbit_rfu_ctrl1; + u32 emc_pmacro_perbit_rfu_ctrl2; + u32 emc_pmacro_perbit_rfu_ctrl3; + u32 emc_pmacro_perbit_rfu_ctrl4; + u32 emc_pmacro_perbit_rfu_ctrl5; + u32 emc_pmacro_perbit_rfu1_ctrl0; + u32 emc_pmacro_perbit_rfu1_ctrl1; + u32 emc_pmacro_perbit_rfu1_ctrl2; + u32 emc_pmacro_perbit_rfu1_ctrl3; + u32 emc_pmacro_perbit_rfu1_ctrl4; + u32 emc_pmacro_perbit_rfu1_ctrl5; + + u32 emc_pmacro_data_pi_ctrl; + u32 emc_pmacro_cmd_pi_ctrl; + + u32 emc_pmacro_ddll_bypass; + + u32 emc_pmacro_ddll_pwrd0; + u32 emc_pmacro_ddll_pwrd1; + u32 emc_pmacro_ddll_pwrd2; + + u32 emc_pmacro_cmd_ctrl0; + u32 emc_pmacro_cmd_ctrl1; + u32 emc_pmacro_cmd_ctrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 mc_emem_adr_cfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 mc_emem_adr_cfg_dev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 mc_emem_adr_cfg_dev1; + + u32 mc_emem_adr_cfg_channel_mask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */ + u32 mc_emem_adr_cfg_bank_mask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 mc_emem_adr_cfg_bank_mask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 mc_emem_adr_cfg_bank_mask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 mc_emem_cfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 mc_emem_arb_cfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 mc_emem_arb_outstanding_req; + + u32 emc_emem_arb_refpb_hp_ctrl; + u32 emc_emem_arb_refpb_bank_ctrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 mc_emem_arb_timing_rcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 mc_emem_arb_timing_rp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 mc_emem_arb_timing_rc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 mc_emem_arb_timing_ras; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 mc_emem_arb_timing_faw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 mc_emem_arb_timing_rrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 mc_emem_arb_timing_rap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 mc_emem_arb_timing_wap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 mc_emem_arb_timing_r2r; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 mc_emem_arb_timing_w2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 mc_emem_arb_timing_r2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 mc_emem_arb_timing_w2r; + + u32 mc_emem_arb_timing_rfcpb; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 mc_emem_arb_da_turns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 mc_emem_arb_da_covers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 mc_emem_arb_misc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 mc_emem_arb_misc1; + u32 mc_emem_arb_misc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 mc_emem_arb_ring1_throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 mc_emem_arb_override; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 mc_emem_arb_override1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 mc_emem_arb_rsv; + + u32 mc_da_cfg0; + u32 mc_emem_arb_timing_ccdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 mc_clken_override; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 mc_stat_control; + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 mc_video_protect_bom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 mc_video_protect_bom_adr_hi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 mc_video_protect_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 mc_video_protect_vpr_override; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 mc_video_protect_vpr_override1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 mc_video_protect_gpu_override0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 mc_video_protect_gpu_override1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 mc_sec_carveout_bom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 mc_sec_carveout_adr_hi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 mc_sec_carveout_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */ + u32 mc_video_protect_write_access; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */ + u32 mc_sec_carveout_protect_write_access; + + u32 mc_generalized_carveout1_bom; + u32 mc_generalized_carveout1_bom_hi; + u32 mc_generalized_carveout1_size_128kb; + u32 mc_generalized_carveout1_access0; + u32 mc_generalized_carveout1_access1; + u32 mc_generalized_carveout1_access2; + u32 mc_generalized_carveout1_access3; + u32 mc_generalized_carveout1_access4; + u32 mc_generalized_carveout1_force_internal_access0; + u32 mc_generalized_carveout1_force_internal_access1; + u32 mc_generalized_carveout1_force_internal_access2; + u32 mc_generalized_carveout1_force_internal_access3; + u32 mc_generalized_carveout1_force_internal_access4; + u32 mc_generalized_carveout1_cfg0; + + u32 mc_generalized_carveout2_bom; + u32 mc_generalized_carveout2_bom_hi; + u32 mc_generalized_carveout2_size_128kb; + u32 mc_generalized_carveout2_access0; + u32 mc_generalized_carveout2_access1; + u32 mc_generalized_carveout2_access2; + u32 mc_generalized_carveout2_access3; + u32 mc_generalized_carveout2_access4; + u32 mc_generalized_carveout2_force_internal_access0; + u32 mc_generalized_carveout2_force_internal_access1; + u32 mc_generalized_carveout2_force_internal_access2; + u32 mc_generalized_carveout2_force_internal_access3; + u32 mc_generalized_carveout2_force_internal_access4; + u32 mc_generalized_carveout2_cfg0; + + u32 mc_generalized_carveout3_bom; + u32 mc_generalized_carveout3_bom_hi; + u32 mc_generalized_carveout3_size_128kb; + u32 mc_generalized_carveout3_access0; + u32 mc_generalized_carveout3_access1; + u32 mc_generalized_carveout3_access2; + u32 mc_generalized_carveout3_access3; + u32 mc_generalized_carveout3_access4; + u32 mc_generalized_carveout3_force_internal_access0; + u32 mc_generalized_carveout3_force_internal_access1; + u32 mc_generalized_carveout3_force_internal_access2; + u32 mc_generalized_carveout3_force_internal_access3; + u32 mc_generalized_carveout3_force_internal_access4; + u32 mc_generalized_carveout3_cfg0; + + u32 mc_generalized_carveout4_bom; + u32 mc_generalized_carveout4_bom_hi; + u32 mc_generalized_carveout4_size_128kb; + u32 mc_generalized_carveout4_access0; + u32 mc_generalized_carveout4_access1; + u32 mc_generalized_carveout4_access2; + u32 mc_generalized_carveout4_access3; + u32 mc_generalized_carveout4_access4; + u32 mc_generalized_carveout4_force_internal_access0; + u32 mc_generalized_carveout4_force_internal_access1; + u32 mc_generalized_carveout4_force_internal_access2; + u32 mc_generalized_carveout4_force_internal_access3; + u32 mc_generalized_carveout4_force_internal_access4; + u32 mc_generalized_carveout4_cfg0; + + u32 mc_generalized_carveout5_bom; + u32 mc_generalized_carveout5_bom_hi; + u32 mc_generalized_carveout5_size_128kb; + u32 mc_generalized_carveout5_access0; + u32 mc_generalized_carveout5_access1; + u32 mc_generalized_carveout5_access2; + u32 mc_generalized_carveout5_access3; + u32 mc_generalized_carveout5_access4; + u32 mc_generalized_carveout5_force_internal_access0; + u32 mc_generalized_carveout5_force_internal_access1; + u32 mc_generalized_carveout5_force_internal_access2; + u32 mc_generalized_carveout5_force_internal_access3; + u32 mc_generalized_carveout5_force_internal_access4; + u32 mc_generalized_carveout5_cfg0; + + /* Specifies enable for CA training */ + u32 emc_ca_training_enable; + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 swizzle_rank_byte_encode; + /* Specifies enable and offset for patched boot rom write */ + u32 boot_rom_patch_control; + /* Specifies data for patched boot rom write */ + u32 boot_rom_patch_data; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 mc_mts_carveout_bom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 mc_mts_carveout_adr_hi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 mc_mts_carveout_size_mb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 mc_mts_carveout_reg_ctrl; + + u32 mc_untranslated_region_check; + + /* Just a place holder for special usage when there is no BCT for certain registers */ + u32 bct_na; +}; + +#endif diff --git a/bdk/mem/sdram_param_t210.h b/bdk/mem/sdram_param_t210.h index 4c6c60a..ed3341b 100644 --- a/bdk/mem/sdram_param_t210.h +++ b/bdk/mem/sdram_param_t210.h @@ -37,7 +37,7 @@ /** * Defines the SDRAM parameter structure */ -typedef struct _sdram_params +typedef struct _sdram_params_t210_t { /* Specifies the type of memory device */ u32 memory_type; @@ -925,6 +925,6 @@ typedef struct _sdram_params u32 mc_mts_carveout_size_mb; /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ u32 mc_mts_carveout_reg_ctrl; -} sdram_params_t; +} sdram_params_t210_t; #endif diff --git a/bdk/mem/sdram_param_t210b01.h b/bdk/mem/sdram_param_t210b01.h new file mode 100644 index 0000000..8bcbed3 --- /dev/null +++ b/bdk/mem/sdram_param_t210b01.h @@ -0,0 +1,989 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _SDRAM_PARAM_T210B01_H_ +#define _SDRAM_PARAM_T210B01_H_ + +typedef struct _sdram_params_t210b01_t +{ + /* Specifies the type of memory device */ + u32 memory_type; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 pllm_input_divider; + /* Specifies the N value for PllM */ + u32 pllm_feedback_divider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 pllm_stable_time; + /* Specifies misc. control bits */ + u32 pllm_setup_control; + /* Specifies the P value for PLLM */ + u32 pllm_post_divider; + /* Specifies value for Charge Pump Gain Control */ + u32 pllm_kcp; + /* Specifies VCO gain */ + u32 pllm_kvco; + /* Spare BCT param */ + u32 emc_bct_spare0; + /* Spare BCT param */ + u32 emc_bct_spare1; + /* Spare BCT param */ + u32 emc_bct_spare2; + /* Spare BCT param */ + u32 emc_bct_spare3; + /* Spare BCT param */ + u32 emc_bct_spare4; + /* Spare BCT param */ + u32 emc_bct_spare5; + /* Spare BCT param */ + u32 emc_bct_spare6; + /* Spare BCT param */ + u32 emc_bct_spare7; + /* Spare BCT param */ + u32 emc_bct_spare8; + /* Spare BCT param */ + u32 emc_bct_spare9; + /* Spare BCT param */ + u32 emc_bct_spare10; + /* Spare BCT param */ + u32 emc_bct_spare11; + /* Spare BCT param */ + u32 emc_bct_spare12; + /* Spare BCT param */ + u32 emc_bct_spare13; + /* Spare BCT param */ + u32 emc_bct_spare_secure0; + /* Spare BCT param */ + u32 emc_bct_spare_secure1; + /* Spare BCT param */ + u32 emc_bct_spare_secure2; + /* Spare BCT param */ + u32 emc_bct_spare_secure3; + /* Spare BCT param */ + u32 emc_bct_spare_secure4; + /* Spare BCT param */ + u32 emc_bct_spare_secure5; + /* Spare BCT param */ + u32 emc_bct_spare_secure6; + /* Spare BCT param */ + u32 emc_bct_spare_secure7; + /* Spare BCT param */ + u32 emc_bct_spare_secure8; + /* Spare BCT param */ + u32 emc_bct_spare_secure9; + /* Spare BCT param */ + u32 emc_bct_spare_secure10; + /* Spare BCT param */ + u32 emc_bct_spare_secure11; + /* Spare BCT param */ + u32 emc_bct_spare_secure12; + /* Spare BCT param */ + u32 emc_bct_spare_secure13; + /* Spare BCT param */ + u32 emc_bct_spare_secure14; + /* Spare BCT param */ + u32 emc_bct_spare_secure15; + /* Spare BCT param */ + u32 emc_bct_spare_secure16; + /* Spare BCT param */ + u32 emc_bct_spare_secure17; + /* Spare BCT param */ + u32 emc_bct_spare_secure18; + /* Spare BCT param */ + u32 emc_bct_spare_secure19; + /* Spare BCT param */ + u32 emc_bct_spare_secure20; + /* Spare BCT param */ + u32 emc_bct_spare_secure21; + /* Spare BCT param */ + u32 emc_bct_spare_secure22; + /* Spare BCT param */ + u32 emc_bct_spare_secure23; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 emc_clock_source; + u32 emc_clock_source_dll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override; + /* enables override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override_enable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 clear_clock2_mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 emc_auto_cal_interval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 emc_auto_cal_config; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 emc_auto_cal_config2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 emc_auto_cal_config3; + u32 emc_auto_cal_config4; + u32 emc_auto_cal_config5; + u32 emc_auto_cal_config6; + u32 emc_auto_cal_config7; + u32 emc_auto_cal_config8; + u32 emc_auto_cal_config9; + + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 emc_auto_cal_vref_sel0; + u32 emc_auto_cal_vref_sel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 emc_auto_cal_channel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 emc_pmacro_auto_cal_cfg0; + u32 emc_pmacro_auto_cal_cfg1; + u32 emc_pmacro_auto_cal_cfg2; + + u32 emc_pmacro_rx_term; + u32 emc_pmacro_dq_tx_drive; + u32 emc_pmacro_ca_tx_drive; + u32 emc_pmacro_cmd_tx_drive; + u32 emc_pmacro_auto_cal_common; + u32 emc_pmacro_zcrtl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 emc_auto_cal_wait; + + u32 emc_xm2_comp_pad_ctrl; + u32 emc_xm2_comp_pad_ctrl2; + u32 emc_xm2_comp_pad_ctrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 emc_adr_cfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 emc_pin_program_wait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 emc_pin_extra_wait; + + u32 emc_pin_gpio_enable; + u32 emc_pin_gpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 emc_timing_control_wait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 emc_rc; + /* Specifies the value for EMC_RFC */ + u32 emc_rfc; + + u32 emc_rfc_pb; + u32 emc_ref_ctrl2; + + /* Specifies the value for EMC_RFC_SLR */ + u32 emc_rfc_slr; + /* Specifies the value for EMC_RAS */ + u32 emc_ras; + /* Specifies the value for EMC_RP */ + u32 emc_rp; + /* Specifies the value for EMC_R2R */ + u32 emc_r2r; + /* Specifies the value for EMC_W2W */ + u32 emc_w2w; + /* Specifies the value for EMC_R2W */ + u32 emc_r2w; + /* Specifies the value for EMC_W2R */ + u32 emc_w2r; + /* Specifies the value for EMC_R2P */ + u32 emc_r2p; + /* Specifies the value for EMC_W2P */ + u32 emc_w2p; + /* Specifies the value for EMC_RD_RCD */ + + u32 emc_tppd; + u32 emc_trtm; + u32 emc_twtm; + u32 emc_tratm; + u32 emc_twatm; + u32 emc_tr2ref; + u32 emc_ccdmw; + + u32 emc_rd_rcd; + /* Specifies the value for EMC_WR_RCD */ + u32 emc_wr_rcd; + /* Specifies the value for EMC_RRD */ + u32 emc_rrd; + /* Specifies the value for EMC_REXT */ + u32 emc_rext; + /* Specifies the value for EMC_WEXT */ + u32 emc_wext; + /* Specifies the value for EMC_WDV */ + u32 emc_wdv; + + u32 emc_wdv_chk; + u32 emc_wsv; + u32 emc_wev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 emc_wdv_mask; + + u32 emc_ws_duration; + u32 emc_we_duration; + + /* Specifies the value for EMC_QUSE */ + u32 emc_quse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 emc_quse_width; + /* Specifies the value for EMC_IBDLY */ + u32 emc_ibdly; + + u32 emc_obdly; + + /* Specifies the value for EMC_EINPUT */ + u32 emc_einput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 emc_einput_duration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 emc_puterm_extra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 emc_puterm_width; + + u32 emc_qrst; + u32 emc_qsafe; + u32 emc_rdv; + u32 emc_rdv_mask; + + u32 emc_rdv_early; + u32 emc_rdv_early_mask; + + /* Specifies the value for EMC_QPOP */ + u32 emc_qpop; + + /* Specifies the value for EMC_REFRESH */ + u32 emc_refresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 emc_burst_refresh_num; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 emc_prerefresh_req_cnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 emc_pdex2wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 emc_pdex2rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 emc_pchg2pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 emc_act2pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 emc_ar2pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 emc_rw2pden; + + u32 emc_cke2pden; + u32 emc_pdex2che; + u32 emc_pdex2mrr; + + /* Specifies the value for EMC_TXSR */ + u32 emc_txsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 emc_txsr_dll; + /* Specifies the value for EMC_TCKE */ + u32 emc_tcke; + /* Specifies the value for EMC_TCKESR */ + u32 emc_tckesr; + /* Specifies the value for EMC_TPD */ + u32 emc_tpd; + /* Specifies the value for EMC_TFAW */ + u32 emc_tfaw; + /* Specifies the value for EMC_TRPAB */ + u32 emc_trpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 emc_tclkstable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 emc_tclkstop; + /* Specifies the value for EMC_TREFBW */ + u32 emc_trefbw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 emc_fbio_cfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 emc_fbio_cfg7; + u32 emc_fbio_cfg8; + + /* Command mapping for CMD brick 0 */ + u32 emc_cmd_mapping_cmd0_0; + u32 emc_cmd_mapping_cmd0_1; + u32 emc_cmd_mapping_cmd0_2; + u32 emc_cmd_mapping_cmd1_0; + u32 emc_cmd_mapping_cmd1_1; + u32 emc_cmd_mapping_cmd1_2; + u32 emc_cmd_mapping_cmd2_0; + u32 emc_cmd_mapping_cmd2_1; + u32 emc_cmd_mapping_cmd2_2; + u32 emc_cmd_mapping_cmd3_0; + u32 emc_cmd_mapping_cmd3_1; + u32 emc_cmd_mapping_cmd3_2; + u32 emc_cmd_mapping_byte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 emc_fbio_spare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 emc_cfg_rsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 emc_mrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 emc_emrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 emc_emrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 emc_emrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 emc_mrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 emc_mrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 emc_mrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 emc_mrw4; + + /* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */ + u32 emc_mrw6; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw8; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw9; + /* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */ + u32 emc_mrw10; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw12; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw13; + /* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */ + u32 emc_mrw14; + + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 emc_mrw_extra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 emc_warm_boot_mrw_extra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 emc_warm_boot_extramode_reg_write_enable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 emc_extramode_reg_write_enable; + + /* Specifies the EMC_MRW reset command value */ + u32 emc_mrw_reset_command; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 emc_mrw_reset_ninit_wait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 emc_mrs_wait_cnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 emc_mrs_wait_cnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 emc_cfg; + /* Specifies the value for EMC_CFG_2 */ + u32 emc_cfg2; + /* Specifies the pipe bypass controls */ + u32 emc_cfg_pipe; + + u32 emc_cfg_pipe_clk; + u32 emc_fdpd_ctrl_cmd_no_ramp; + u32 emc_cfg_update; + + /* Specifies the value for EMC_DBG */ + u32 emc_dbg; + + u32 emc_dbg_write_mux; + + /* Specifies the value for EMC_CMDQ */ + u32 emc_cmd_q; + /* Specifies the value for EMC_MC2EMCQ */ + u32 emc_mc2emc_q; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 emc_dyn_self_ref_control; + + /* Specifies the value for MEM_INIT_DONE */ + u32 ahb_arbitration_xbar_ctrl_meminit_done; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 emc_cfg_dig_dll; + u32 emc_cfg_dig_dll_1; + + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 emc_cfg_dig_dll_period; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 emc_dev_select; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 emc_sel_dpd_ctrl; + + /* Pads trimmer delays */ + u32 emc_fdpd_ctrl_dq; + u32 emc_fdpd_ctrl_cmd; + u32 emc_pmacro_ib_vref_dq_0; + u32 emc_pmacro_ib_vref_dq_1; + u32 emc_pmacro_ib_vref_dqs_0; + u32 emc_pmacro_ib_vref_dqs_1; + u32 emc_pmacro_ib_rxrt; + u32 emc_cfg_pipe1; + u32 emc_cfg_pipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 emc_pmacro_quse_ddll_rank0_0; + u32 emc_pmacro_quse_ddll_rank0_1; + u32 emc_pmacro_quse_ddll_rank0_2; + u32 emc_pmacro_quse_ddll_rank0_3; + u32 emc_pmacro_quse_ddll_rank0_4; + u32 emc_pmacro_quse_ddll_rank0_5; + u32 emc_pmacro_quse_ddll_rank1_0; + u32 emc_pmacro_quse_ddll_rank1_1; + u32 emc_pmacro_quse_ddll_rank1_2; + u32 emc_pmacro_quse_ddll_rank1_3; + u32 emc_pmacro_quse_ddll_rank1_4; + u32 emc_pmacro_quse_ddll_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dq_rank0_0; + u32 emc_pmacro_ob_ddll_long_dq_rank0_1; + u32 emc_pmacro_ob_ddll_long_dq_rank0_2; + u32 emc_pmacro_ob_ddll_long_dq_rank0_3; + u32 emc_pmacro_ob_ddll_long_dq_rank0_4; + u32 emc_pmacro_ob_ddll_long_dq_rank0_5; + u32 emc_pmacro_ob_ddll_long_dq_rank1_0; + u32 emc_pmacro_ob_ddll_long_dq_rank1_1; + u32 emc_pmacro_ob_ddll_long_dq_rank1_2; + u32 emc_pmacro_ob_ddll_long_dq_rank1_3; + u32 emc_pmacro_ob_ddll_long_dq_rank1_4; + u32 emc_pmacro_ob_ddll_long_dq_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_5; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_5; + + u32 emc_pmacro_ib_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_3; + + u32 emc_pmacro_ddll_long_cmd_0; + u32 emc_pmacro_ddll_long_cmd_1; + u32 emc_pmacro_ddll_long_cmd_2; + u32 emc_pmacro_ddll_long_cmd_3; + u32 emc_pmacro_ddll_long_cmd_4; + u32 emc_pmacro_ddll_short_cmd_0; + u32 emc_pmacro_ddll_short_cmd_1; + u32 emc_pmacro_ddll_short_cmd_2; + + u32 emc_pmacro_ddll_periodic_offset; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 warm_boot_wait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 emc_odt_write; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 emc_zcal_interval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 emc_zcal_wait_cnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 emc_zcal_mrw_cmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 emc_mrs_reset_dll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 emc_zcal_init_dev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 emc_zcal_init_dev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 emc_zcal_init_wait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 emc_zcal_warm_cold_boot_enables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 emc_mrw_lpddr2zcal_warm_boot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 emc_zqcal_ddr3_warm_boot; + + u32 emc_zqcal_lpddr4_warm_boot; + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 emc_zcal_warm_boot_wait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 emc_mrs_warm_boot_enable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 emc_mrs_reset_dll_wait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 emc_mrs_extra; + /* Specifies the extra MRS command at warm boot */ + u32 emc_warm_boot_mrs_extra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 emc_emrs_ddr2_dll_enable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 emc_mrs_ddr2_dll_reset; + /* Specifies the EMRS command to set OCD calibration */ + u32 emc_emrs_ddr2_ocd_calib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 emc_ddr2_wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 emc_clken_override; + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 emc_extra_refresh_num; + /* Specifies the master override for all EMC clocks */ + u32 emc_clken_override_allwarm_boot; + /* Specifies the master override for all MC clocks */ + u32 mc_clken_override_allwarm_boot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 emc_cfg_dig_dll_period_warm_boot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 pmc_vddp_sel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 pmc_vddp_sel_wait; + /* Specifies the value for PMC_DDR_CFG */ + u32 pmc_ddr_cfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req_wait; + + u32 pmc_io_dpd4_req_wait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 pmc_reg_short; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 pmc_no_io_power; + + u32 pmc_ddr_ctrl_wait; + u32 pmc_ddr_ctrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 emc_acpd_control; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 emc_swizzle_rank0_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 emc_swizzle_rank0_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 emc_swizzle_rank0_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 emc_swizzle_rank0_byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 emc_swizzle_rank1_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 emc_swizzle_rank1_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 emc_swizzle_rank1_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 emc_swizzle_rank1_byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 emc_txdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 emc_data_brlshft0; + u32 emc_data_brlshft1; + + u32 emc_dqs_brlshft0; + u32 emc_dqs_brlshft1; + + u32 emc_cmd_brlshft0; + u32 emc_cmd_brlshft1; + u32 emc_cmd_brlshft2; + u32 emc_cmd_brlshft3; + + u32 emc_quse_brlshft0; + u32 emc_quse_brlshft1; + u32 emc_quse_brlshft2; + u32 emc_quse_brlshft3; + + u32 emc_dll_cfg0; + u32 emc_dll_cfg1; + + u32 emc_pmc_scratch1; + u32 emc_pmc_scratch2; + u32 emc_pmc_scratch3; + + u32 emc_pmacro_pad_cfg_ctrl; + + u32 emc_pmacro_vttgen_ctrl0; + u32 emc_pmacro_vttgen_ctrl1; + u32 emc_pmacro_vttgen_ctrl2; + u32 emc_pmacro_dsr_vttgen_ctrl0; + u32 emc_pmacro_brick_ctrl_rfu1; + u32 emc_pmacro_cmd_brick_ctrl_fdpd; + u32 emc_pmacro_brick_ctrl_rfu2; + u32 emc_pmacro_data_brick_ctrl_fdpd; + u32 emc_pmacro_bg_bias_ctrl0; + u32 emc_pmacro_data_pad_rx_ctrl; + u32 emc_pmacro_cmd_pad_rx_ctrl; + u32 emc_pmacro_data_rx_term_mode; + u32 emc_pmacro_cmd_rx_term_mode; + u32 emc_pmacro_data_pad_tx_ctrl; + u32 emc_pmacro_cmd_pad_tx_ctrl; + u32 emc_cfg3; + + u32 emc_pmacro_tx_pwrd0; + u32 emc_pmacro_tx_pwrd1; + u32 emc_pmacro_tx_pwrd2; + u32 emc_pmacro_tx_pwrd3; + u32 emc_pmacro_tx_pwrd4; + u32 emc_pmacro_tx_pwrd5; + + u32 emc_config_sample_delay; + + u32 emc_pmacro_brick_mapping0; + u32 emc_pmacro_brick_mapping1; + u32 emc_pmacro_brick_mapping2; + + u32 emc_pmacro_tx_sel_clk_src0; + u32 emc_pmacro_tx_sel_clk_src1; + u32 emc_pmacro_tx_sel_clk_src2; + u32 emc_pmacro_tx_sel_clk_src3; + u32 emc_pmacro_tx_sel_clk_src4; + u32 emc_pmacro_tx_sel_clk_src5; + + u32 emc_pmacro_perbit_fgcg_ctrl0; + u32 emc_pmacro_perbit_fgcg_ctrl1; + u32 emc_pmacro_perbit_fgcg_ctrl2; + u32 emc_pmacro_perbit_fgcg_ctrl3; + u32 emc_pmacro_perbit_fgcg_ctrl4; + u32 emc_pmacro_perbit_fgcg_ctrl5; + u32 emc_pmacro_perbit_rfu_ctrl0; + u32 emc_pmacro_perbit_rfu_ctrl1; + u32 emc_pmacro_perbit_rfu_ctrl2; + u32 emc_pmacro_perbit_rfu_ctrl3; + u32 emc_pmacro_perbit_rfu_ctrl4; + u32 emc_pmacro_perbit_rfu_ctrl5; + u32 emc_pmacro_perbit_rfu1_ctrl0; + u32 emc_pmacro_perbit_rfu1_ctrl1; + u32 emc_pmacro_perbit_rfu1_ctrl2; + u32 emc_pmacro_perbit_rfu1_ctrl3; + u32 emc_pmacro_perbit_rfu1_ctrl4; + u32 emc_pmacro_perbit_rfu1_ctrl5; + + u32 emc_pmacro_data_pi_ctrl; + u32 emc_pmacro_cmd_pi_ctrl; + + u32 emc_pmacro_ddll_bypass; + + u32 emc_pmacro_ddll_pwrd0; + u32 emc_pmacro_ddll_pwrd1; + u32 emc_pmacro_ddll_pwrd2; + + u32 emc_pmacro_cmd_ctrl0; + u32 emc_pmacro_cmd_ctrl1; + u32 emc_pmacro_cmd_ctrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 mc_emem_adr_cfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 mc_emem_adr_cfg_dev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 mc_emem_adr_cfg_dev1; + + u32 mc_emem_adr_cfg_channel_mask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */ + u32 mc_emem_adr_cfg_bank_mask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 mc_emem_adr_cfg_bank_mask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 mc_emem_adr_cfg_bank_mask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 mc_emem_cfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 mc_emem_arb_cfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 mc_emem_arb_outstanding_req; + + u32 emc_emem_arb_refpb_hp_ctrl; + u32 emc_emem_arb_refpb_bank_ctrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 mc_emem_arb_timing_rcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 mc_emem_arb_timing_rp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 mc_emem_arb_timing_rc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 mc_emem_arb_timing_ras; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 mc_emem_arb_timing_faw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 mc_emem_arb_timing_rrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 mc_emem_arb_timing_rap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 mc_emem_arb_timing_wap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 mc_emem_arb_timing_r2r; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 mc_emem_arb_timing_w2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 mc_emem_arb_timing_r2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 mc_emem_arb_timing_w2r; + + u32 mc_emem_arb_timing_rfcpb; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 mc_emem_arb_da_turns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 mc_emem_arb_da_covers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 mc_emem_arb_misc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 mc_emem_arb_misc1; + u32 mc_emem_arb_misc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 mc_emem_arb_ring1_throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 mc_emem_arb_override; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 mc_emem_arb_override1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 mc_emem_arb_rsv; + + u32 mc_da_cfg0; + u32 mc_emem_arb_timing_ccdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 mc_clken_override; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 mc_stat_control; + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 mc_video_protect_bom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 mc_video_protect_bom_adr_hi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 mc_video_protect_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 mc_video_protect_vpr_override; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 mc_video_protect_vpr_override1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 mc_video_protect_gpu_override0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 mc_video_protect_gpu_override1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 mc_sec_carveout_bom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 mc_sec_carveout_adr_hi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 mc_sec_carveout_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */ + u32 mc_video_protect_write_access; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */ + u32 mc_sec_carveout_protect_write_access; + + u32 mc_generalized_carveout1_bom; + u32 mc_generalized_carveout1_bom_hi; + u32 mc_generalized_carveout1_size_128kb; + u32 mc_generalized_carveout1_access0; + u32 mc_generalized_carveout1_access1; + u32 mc_generalized_carveout1_access2; + u32 mc_generalized_carveout1_access3; + u32 mc_generalized_carveout1_access4; + u32 mc_generalized_carveout1_force_internal_access0; + u32 mc_generalized_carveout1_force_internal_access1; + u32 mc_generalized_carveout1_force_internal_access2; + u32 mc_generalized_carveout1_force_internal_access3; + u32 mc_generalized_carveout1_force_internal_access4; + u32 mc_generalized_carveout1_cfg0; + + u32 mc_generalized_carveout2_bom; + u32 mc_generalized_carveout2_bom_hi; + u32 mc_generalized_carveout2_size_128kb; + u32 mc_generalized_carveout2_access0; + u32 mc_generalized_carveout2_access1; + u32 mc_generalized_carveout2_access2; + u32 mc_generalized_carveout2_access3; + u32 mc_generalized_carveout2_access4; + u32 mc_generalized_carveout2_force_internal_access0; + u32 mc_generalized_carveout2_force_internal_access1; + u32 mc_generalized_carveout2_force_internal_access2; + u32 mc_generalized_carveout2_force_internal_access3; + u32 mc_generalized_carveout2_force_internal_access4; + u32 mc_generalized_carveout2_cfg0; + + u32 mc_generalized_carveout3_bom; + u32 mc_generalized_carveout3_bom_hi; + u32 mc_generalized_carveout3_size_128kb; + u32 mc_generalized_carveout3_access0; + u32 mc_generalized_carveout3_access1; + u32 mc_generalized_carveout3_access2; + u32 mc_generalized_carveout3_access3; + u32 mc_generalized_carveout3_access4; + u32 mc_generalized_carveout3_force_internal_access0; + u32 mc_generalized_carveout3_force_internal_access1; + u32 mc_generalized_carveout3_force_internal_access2; + u32 mc_generalized_carveout3_force_internal_access3; + u32 mc_generalized_carveout3_force_internal_access4; + u32 mc_generalized_carveout3_cfg0; + + u32 mc_generalized_carveout4_bom; + u32 mc_generalized_carveout4_bom_hi; + u32 mc_generalized_carveout4_size_128kb; + u32 mc_generalized_carveout4_access0; + u32 mc_generalized_carveout4_access1; + u32 mc_generalized_carveout4_access2; + u32 mc_generalized_carveout4_access3; + u32 mc_generalized_carveout4_access4; + u32 mc_generalized_carveout4_force_internal_access0; + u32 mc_generalized_carveout4_force_internal_access1; + u32 mc_generalized_carveout4_force_internal_access2; + u32 mc_generalized_carveout4_force_internal_access3; + u32 mc_generalized_carveout4_force_internal_access4; + u32 mc_generalized_carveout4_cfg0; + + u32 mc_generalized_carveout5_bom; + u32 mc_generalized_carveout5_bom_hi; + u32 mc_generalized_carveout5_size_128kb; + u32 mc_generalized_carveout5_access0; + u32 mc_generalized_carveout5_access1; + u32 mc_generalized_carveout5_access2; + u32 mc_generalized_carveout5_access3; + u32 mc_generalized_carveout5_access4; + u32 mc_generalized_carveout5_force_internal_access0; + u32 mc_generalized_carveout5_force_internal_access1; + u32 mc_generalized_carveout5_force_internal_access2; + u32 mc_generalized_carveout5_force_internal_access3; + u32 mc_generalized_carveout5_force_internal_access4; + u32 mc_generalized_carveout5_cfg0; + + /* Specifies enable for CA training */ + u32 emc_ca_training_enable; + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 swizzle_rank_byte_encode; + /* Specifies enable and offset for patched boot rom write */ + u32 boot_rom_patch_control; + /* Specifies data for patched boot rom write */ + u32 boot_rom_patch_data; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 mc_mts_carveout_bom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 mc_mts_carveout_adr_hi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 mc_mts_carveout_size_mb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 mc_mts_carveout_reg_ctrl; + + /* Specifies the clients that are allowed to access untranslated memory */ + u32 mc_untranslated_region_check; + + /* Just a place holder for special usage when there is no BCT for certain registers */ + u32 bct_na; +} sdram_params_t210b01_t; + +#endif diff --git a/bdk/memory_map.h b/bdk/memory_map.h index 6a83651..f72a0c5 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -20,9 +20,16 @@ //#define IPL_STACK_TOP 0x4003FF00 /* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ /* --- IPL: 0x40003000 - 0x40028000 --- */ +#define LDR_LOAD_ADDR 0x40007000 + #define IPL_LOAD_ADDR 0x40003000 #define IPL_SZ_MAX 0x20000 // 128KB. -//#define IRAM_LIB_ADDR 0x4002B000 + +/* --- XUSB EP context and TRB ring buffers --- */ +#define XUSB_RING_ADDR 0x40020000 + +#define SECMON_MIN_START 0x4002B000 + #define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. #define CBFS_DRAM_EN_ADDR 0x4003e000 // u32. @@ -45,6 +52,10 @@ #define NX_BIS_CACHE_ADDR RAM_DISK_ADDR #define RAM_DISK_SZ 0x41000000 // 1040MB. +// L4T Kernel Panic Storage (PSTORE). +#define PSTORE_ADDR 0xB0000000 +#define PSTORE_SZ 0x200000 // 2MB. + //#define DRAM_LIB_ADDR 0xE0000000 /* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. diff --git a/bdk/power/bm92t36.c b/bdk/power/bm92t36.c new file mode 100644 index 0000000..d1496f7 --- /dev/null +++ b/bdk/power/bm92t36.c @@ -0,0 +1,99 @@ +/* + * USB-PD driver for Nintendo Switch's TI BM92T36 + * + * Copyright (c) 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 . + */ + +#include + +#include "bm92t36.h" +#include +#include + +#define ALERT_STATUS_REG 0x2 +#define STATUS1_REG 0x3 +#define STATUS2_REG 0x4 +#define COMMAND_REG 0x5 +#define CONFIG1_REG 0x6 +#define DEV_CAPS_REG 0x7 +#define READ_PDOS_SRC_REG 0x8 +#define CONFIG2_REG 0x17 +#define DP_STATUS_REG 0x18 +#define DP_ALERT_EN_REG 0x19 +#define VENDOR_CONFIG_REG 0x1A +#define AUTO_NGT_FIXED_REG 0x20 +#define AUTO_NGT_BATT_REG 0x23 +#define SYS_CONFIG1_REG 0x26 +#define SYS_CONFIG2_REG 0x27 +#define CURRENT_PDO_REG 0x28 +#define CURRENT_RDO_REG 0x2B +#define ALERT_ENABLE_REG 0x2E +#define SYS_CONFIG3_REG 0x2F +#define SET_RDO_REG 0x30 +#define PDOS_SNK_REG 0x33 +#define PDOS_SRC_PROV_REG 0x3C +#define FW_TYPE_REG 0x4B +#define FW_REVISION_REG 0x4C +#define MAN_ID_REG 0x4D +#define DEV_ID_REG 0x4E +#define REV_ID_REG 0x4F +#define INCOMING_VDM_REG 0x50 +#define OUTGOING_VDM_REG 0x60 + +#define STATUS1_INSERT BIT(7) // Cable inserted. + +typedef struct _pd_object_t { + unsigned int amp:10; + unsigned int volt:10; + unsigned int info:10; + unsigned int type:2; +} __attribute__((packed)) pd_object_t; + +static int _bm92t36_read_reg(u8 *buf, u32 size, u32 reg) +{ + return i2c_recv_buf_big(buf, size, I2C_1, BM92T36_I2C_ADDR, reg); +} + +void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd) +{ + u8 buf[32]; + pd_object_t pdos[7]; + + if (inserted) + { + _bm92t36_read_reg(buf, 2, STATUS1_REG); + *inserted = buf[0] & STATUS1_INSERT ? true : false; + } + + if (usb_pd) + { + _bm92t36_read_reg(buf, 29, READ_PDOS_SRC_REG); + memcpy(pdos, &buf[1], 28); + + memset(usb_pd, 0, sizeof(usb_pd_objects_t)); + usb_pd->pdo_no = buf[0] / sizeof(pd_object_t); + + for (u32 i = 0; i < usb_pd->pdo_no; i++) + { + usb_pd->pdos[i].amperage = pdos[i].amp * 10; + usb_pd->pdos[i].voltage = (pdos[i].volt * 50) / 1000; + } + + _bm92t36_read_reg(buf, 5, CURRENT_PDO_REG); + memcpy(pdos, &buf[1], 4); + usb_pd->selected_pdo.amperage = pdos[0].amp * 10; + usb_pd->selected_pdo.voltage = (pdos[0].volt * 50) / 1000; + } +} diff --git a/bdk/power/bm92t36.h b/bdk/power/bm92t36.h new file mode 100644 index 0000000..e6740d8 --- /dev/null +++ b/bdk/power/bm92t36.h @@ -0,0 +1,41 @@ +/* + * USB-PD driver for Nintendo Switch's TI BM92T36 + * + * Copyright (c) 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 . + */ + +#ifndef __BM92T36_H_ +#define __BM92T36_H_ + +#include + +#define BM92T36_I2C_ADDR 0x18 + +typedef struct _usb_pd_object_t +{ + u32 amperage; + u32 voltage; +} usb_pd_object_t; + +typedef struct _usb_pd_objects_t +{ + u32 pdo_no; + usb_pd_object_t pdos[7]; + usb_pd_object_t selected_pdo; +} usb_pd_objects_t; + +void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd); + +#endif diff --git a/bdk/power/max17050.c b/bdk/power/max17050.c index 2491466..a561724 100644 --- a/bdk/power/max17050.c +++ b/bdk/power/max17050.c @@ -26,17 +26,19 @@ #include #include +#define BASE_SNS_UOHM 5000 + /* Status register bits */ -#define STATUS_POR_BIT (1 << 1) -#define STATUS_BST_BIT (1 << 3) -#define STATUS_VMN_BIT (1 << 8) -#define STATUS_TMN_BIT (1 << 9) -#define STATUS_SMN_BIT (1 << 10) -#define STATUS_BI_BIT (1 << 11) -#define STATUS_VMX_BIT (1 << 12) -#define STATUS_TMX_BIT (1 << 13) -#define STATUS_SMX_BIT (1 << 14) -#define STATUS_BR_BIT (1 << 15) +#define STATUS_POR_BIT BIT(1) +#define STATUS_BST_BIT BIT(3) +#define STATUS_VMN_BIT BIT(8) +#define STATUS_TMN_BIT BIT(9) +#define STATUS_SMN_BIT BIT(10) +#define STATUS_BI_BIT BIT(11) +#define STATUS_VMX_BIT BIT(12) +#define STATUS_TMX_BIT BIT(13) +#define STATUS_SMX_BIT BIT(14) +#define STATUS_BR_BIT BIT(15) #define VFSOC0_LOCK 0x0000 #define VFSOC0_UNLOCK 0x0080 @@ -85,31 +87,31 @@ int max17050_get_property(enum MAX17050_reg reg, int *value) break; case MAX17050_VCELL: // Voltage now. data = max17050_get_reg(MAX17050_VCELL); - *value = data * 625 / 8 / 1000; + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ battery_voltage = *value; break; case MAX17050_AvgVCELL: // Voltage avg. data = max17050_get_reg(MAX17050_AvgVCELL); - *value = data * 625 / 8 / 1000; + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ break; case MAX17050_OCVInternal: // Voltage ocv. data = max17050_get_reg(MAX17050_OCVInternal); - *value = data * 625 / 8 / 1000; + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ break; case MAX17050_RepSOC: // Capacity %. *value = max17050_get_reg(MAX17050_RepSOC); break; case MAX17050_DesignCap: // Charge full design. data = max17050_get_reg(MAX17050_DesignCap); - *value = data * 5 / 10; + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_FullCAP: // Charge full. data = max17050_get_reg(MAX17050_FullCAP); - *value = data * 5 / 10; + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_RepCap: // Charge now. data = max17050_get_reg(MAX17050_RepCap); - *value = data * 5 / 10; + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_TEMP: // Temp. data = max17050_get_reg(MAX17050_TEMP); @@ -119,12 +121,12 @@ int max17050_get_property(enum MAX17050_reg reg, int *value) case MAX17050_Current: // Current now. data = max17050_get_reg(MAX17050_Current); *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + *value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN); break; case MAX17050_AvgCurrent: // Current avg. data = max17050_get_reg(MAX17050_AvgCurrent); *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + *value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN); break; default: return -1; diff --git a/bdk/power/max17050.h b/bdk/power/max17050.h index 254aca3..a9b3d37 100644 --- a/bdk/power/max17050.h +++ b/bdk/power/max17050.h @@ -1,6 +1,5 @@ /* * Fuel gauge driver for Nintendo Switch's Maxim 17050 - * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. * * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham @@ -26,8 +25,11 @@ #include -#define MAX17050_STATUS_BattAbsent (1 << 3) -#define MAX17050_DEFAULT_SNS_RESISTOR 10000 +/* Board default values */ +#define MAX17050_BOARD_CGAIN 2 /* Actual: 1.99993 */ +#define MAX17050_BOARD_SNS_RESISTOR_UOHM 5000 /* 0.005 Ohm */ + +#define MAX17050_STATUS_BattAbsent BIT(3) /* Consider RepCap which is less then 10 units below FullCAP full */ #define MAX17050_FULL_THRESHOLD 10 diff --git a/bdk/power/max77620.h b/bdk/power/max77620.h index 26ea855..23ee299 100644 --- a/bdk/power/max77620.h +++ b/bdk/power/max77620.h @@ -16,13 +16,7 @@ /* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ #define MAX77620_REG_CNFGGLBL1 0x00 -#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) -#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) -#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBRSTEN BIT(0) #define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E #define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) @@ -32,14 +26,20 @@ #define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) -#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBHYST (BIT(5) | BIT(4)) +#define MAX77620_CNFGGLBL1_MPPLD BIT(6) +#define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7) #define MAX77620_REG_CNFGGLBL2 0x01 #define MAX77620_REG_CNFGGLBL3 0x02 #define MAX77620_WDTC_MASK 0x3 -#define MAX77620_WDTOFFC (1 << 4) -#define MAX77620_WDTSLPC (1 << 3) -#define MAX77620_WDTEN (1 << 2) +#define MAX77620_WDTEN BIT(2) +#define MAX77620_WDTSLPC BIT(3) +#define MAX77620_WDTOFFC BIT(4) #define MAX77620_TWD_MASK 0x3 #define MAX77620_TWD_2s 0x0 #define MAX77620_TWD_16s 0x1 @@ -47,15 +47,15 @@ #define MAX77620_TWD_128s 0x3 #define MAX77620_REG_CNFG1_32K 0x03 -#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) +#define MAX77620_CNFG1_32K_OUT0_EN BIT(2) #define MAX77620_REG_CNFGBBC 0x04 -#define MAX77620_CNFGBBC_ENABLE (1 << 0) +#define MAX77620_CNFGBBC_ENABLE BIT(0) #define MAX77620_CNFGBBC_CURRENT_MASK 0x06 #define MAX77620_CNFGBBC_CURRENT_SHIFT 1 #define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 #define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 -#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE BIT(5) #define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 #define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 #define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) @@ -64,19 +64,19 @@ #define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_REG_IRQTOP 0x05 -#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) -#define MAX77620_IRQ_TOP_SD_MASK (1 << 6) -#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) -#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) -#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) -#define MAX77620_IRQ_TOP_32K_MASK (1 << 2) -#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) +#define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1) +#define MAX77620_IRQ_TOP_32K_MASK BIT(2) +#define MAX77620_IRQ_TOP_RTC_MASK BIT(3) +#define MAX77620_IRQ_TOP_GPIO_MASK BIT(4) +#define MAX77620_IRQ_TOP_LDO_MASK BIT(5) +#define MAX77620_IRQ_TOP_SD_MASK BIT(6) +#define MAX77620_IRQ_TOP_GLBL_MASK BIT(7) #define MAX77620_REG_INTLBT 0x06 #define MAX77620_REG_IRQTOPM 0x0D -#define MAX77620_IRQ_LBM_MASK (1 << 3) -#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) -#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) +#define MAX77620_IRQ_TJALRM2_MASK BIT(1) +#define MAX77620_IRQ_TJALRM1_MASK BIT(2) +#define MAX77620_IRQ_LBM_MASK BIT(3) #define MAX77620_REG_IRQSD 0x07 #define MAX77620_REG_IRQ_LVL2_L0_7 0x08 @@ -86,7 +86,7 @@ #define MAX77620_REG_NVERC 0x0C #define MAX77620_REG_INTENLBT 0x0E -#define MAX77620_GLBLM_MASK (1 << 0) +#define MAX77620_GLBLM_MASK BIT(0) #define MAX77620_REG_IRQMASKSD 0x0F #define MAX77620_REG_IRQ_MSK_L0_7 0x10 @@ -108,11 +108,11 @@ #define MAX77620_LDO_VOLT_MASK 0x3F #define MAX77620_REG_DVSSD0 0x1B #define MAX77620_REG_DVSSD1 0x1C -#define MAX77620_REG_SD0_CFG 0x1D -#define MAX77620_REG_SD1_CFG 0x1E -#define MAX77620_REG_SD2_CFG 0x1F -#define MAX77620_REG_SD3_CFG 0x20 -#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_REG_SD0_CFG 0x1D // SD CNFG1. +#define MAX77620_REG_SD1_CFG 0x1E // SD CNFG1. +#define MAX77620_REG_SD2_CFG 0x1F // SD CNFG1. +#define MAX77620_REG_SD3_CFG 0x20 // SD CNFG1. +#define MAX77620_REG_SD4_CFG 0x21 // SD CNFG1. #define MAX77620_REG_SD_CFG2 0x22 #define MAX77620_REG_LDO0_CFG 0x23 #define MAX77620_REG_LDO0_CFG2 0x24 @@ -132,23 +132,23 @@ #define MAX77620_REG_LDO7_CFG2 0x32 #define MAX77620_REG_LDO8_CFG 0x33 #define MAX77620_REG_LDO8_CFG2 0x34 +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW 0 +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX20024_LDO_CFG2_MPOK_MASK BIT(2) #define MAX77620_LDO_POWER_MODE_MASK 0xC0 #define MAX77620_LDO_POWER_MODE_SHIFT 6 #define MAX77620_POWER_MODE_NORMAL 3 #define MAX77620_POWER_MODE_LPM 2 #define MAX77620_POWER_MODE_GLPM 1 #define MAX77620_POWER_MODE_DISABLE 0 -#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) -#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) -#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) -#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) -#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) -#define MAX77620_LDO_CFG2_SS_SLOW 0 #define MAX77620_REG_LDO_CFG3 0x35 -#define MAX77620_TRACK4_MASK (1 << 5) #define MAX77620_TRACK4_SHIFT 5 +#define MAX77620_TRACK4_MASK (1 << MAX77620_TRACK4_SHIFT) #define MAX77620_LDO_SLEW_RATE_MASK 0x1 @@ -183,19 +183,19 @@ #define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) #define MAX77620_REG_ONOFFCNFG1 0x41 -#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) -#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 -#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 -#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) -#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) #define MAX20024_ONOFFCNFG1_CLRSE 0x18 +#define MAX77620_ONOFFCNFG1_PWR_OFF BIT(1) +#define MAX77620_ONOFFCNFG1_SLPEN BIT(2) +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_SFT_RST BIT(7) #define MAX77620_REG_ONOFFCNFG2 0x42 -#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) -#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) -#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) -#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) -#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) +#define MAX77620_ONOFFCNFG2_WK_EN0 BIT(0) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5) +#define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6) +#define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7) /* FPS Registers */ #define MAX77620_REG_FPS_CFG0 0x43 @@ -259,8 +259,8 @@ #define MAX77620_CID_DIDM_SHIFT 4 /* CNCG2SD */ -#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) -#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) +#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) /* Device Identification Metal */ #define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) @@ -272,29 +272,29 @@ #define MAX77620_SD_SR_SHIFT 6 #define MAX77620_SD_POWER_MODE_MASK 0x30 #define MAX77620_SD_POWER_MODE_SHIFT 4 -#define MAX77620_SD_CFG1_ADE_MASK (1 << 3) +#define MAX77620_SD_CFG1_ADE_MASK BIT(3) #define MAX77620_SD_CFG1_ADE_DISABLE 0 -#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) +#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3) #define MAX77620_SD_FPWM_MASK 0x04 #define MAX77620_SD_FPWM_SHIFT 2 #define MAX77620_SD_FSRADE_MASK 0x01 #define MAX77620_SD_FSRADE_SHIFT 0 -#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) +#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2) #define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 -#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) -#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) -#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) +#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) +#define MAX20024_SD_CFG1_MPOK_MASK BIT(1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 -#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) -#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) -#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) -#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) -#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) -#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) -#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) -#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) -#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 BIT(0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 BIT(2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 BIT(3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 BIT(4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 BIT(5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 BIT(6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 BIT(7) /* Interrupts */ enum { diff --git a/bdk/power/max7762x.c b/bdk/power/max7762x.c index 425ce1f..c32cf76 100644 --- a/bdk/power/max7762x.c +++ b/bdk/power/max7762x.c @@ -61,17 +61,19 @@ static const max77620_regulator_t _pmic_regulators[] = { { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, - { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } + { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 2800000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } }; -static void _max77620_try_set_reg(u8 reg, u8 val) +static void _max77620_set_reg(u8 reg, u8 val) { - u8 tmp; - do + u32 retries = 100; + while (retries) { - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); - tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); - } while (val != tmp); + if (i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val)) + break; + usleep(100); + retries--; + } } int max77620_regulator_get_status(u32 id) @@ -93,7 +95,7 @@ int max77620_regulator_config_fps(u32 id) const max77620_regulator_t *reg = &_pmic_regulators[id]; - _max77620_try_set_reg(reg->fps_addr, + _max77620_set_reg(reg->fps_addr, (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); return 1; @@ -112,7 +114,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); + _max77620_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -131,7 +133,7 @@ int max77620_regulator_enable(u32 id, int enable) val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); else val &= ~reg->enable_mask; - _max77620_try_set_reg(addr, val); + _max77620_set_reg(addr, val); usleep(1000); return 1; @@ -150,7 +152,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); + _max77620_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -166,12 +168,12 @@ void max77620_config_default() if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) max77620_regulator_enable(i, 1); } - _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); + _max77620_set_reg(MAX77620_REG_SD_CFG2, 4); } void max77620_low_battery_monitor_config(bool enable) { - _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, + _max77620_set_reg(MAX77620_REG_CNFGGLBL1, MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/bdk/power/max7762x.h b/bdk/power/max7762x.h index f60c3b2..dd06bf7 100644 --- a/bdk/power/max7762x.h +++ b/bdk/power/max7762x.h @@ -69,7 +69,7 @@ #define MAX77621_CONTROL2_REG 3 /* MAX77621_VOUT */ -#define MAX77621_VOUT_ENABLE (1 << 7) +#define MAX77621_VOUT_ENABLE BIT(7) #define MAX77621_VOUT_MASK 0x7F #define MAX77621_VOUT_0_95V 0x37 #define MAX77621_VOUT_1_09V 0x4F @@ -78,12 +78,12 @@ #define MAX77621_DVS_VOUT_MASK 0x7F /* MAX77621_CONTROL1 */ -#define MAX77621_SNS_ENABLE (1 << 7) -#define MAX77621_FPWM_EN_M (1 << 6) -#define MAX77621_NFSR_ENABLE (1 << 5) -#define MAX77621_AD_ENABLE (1 << 4) -#define MAX77621_BIAS_ENABLE (1 << 3) -#define MAX77621_FREQSHIFT_9PER (1 << 2) +#define MAX77621_FREQSHIFT_9PER BIT(2) +#define MAX77621_BIAS_ENABLE BIT(3) +#define MAX77621_AD_ENABLE BIT(4) +#define MAX77621_NFSR_ENABLE BIT(5) +#define MAX77621_FPWM_EN_M BIT(6) +#define MAX77621_SNS_ENABLE BIT(7) #define MAX77621_RAMP_12mV_PER_US 0x0 #define MAX77621_RAMP_25mV_PER_US 0x1 @@ -92,10 +92,10 @@ #define MAX77621_RAMP_MASK 0x3 /* MAX77621_CONTROL2 */ -#define MAX77621_WDTMR_ENABLE (1 << 6) -#define MAX77621_DISCH_ENBABLE (1 << 5) -#define MAX77621_FT_ENABLE (1 << 4) -#define MAX77621_T_JUNCTION_120 (1 << 7) +#define MAX77621_FT_ENABLE BIT(4) +#define MAX77621_DISCH_ENBABLE BIT(5) +#define MAX77621_WDTMR_ENABLE BIT(6) +#define MAX77621_T_JUNCTION_120 BIT(7) #define MAX77621_CKKADV_TRIP_DISABLE 0xC #define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 diff --git a/bdk/power/max77812.h b/bdk/power/max77812.h new file mode 100644 index 0000000..f8ac3fb --- /dev/null +++ b/bdk/power/max77812.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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 . + */ + +#ifndef _MAX77812_H_ +#define _MAX77812_H_ + +#define MAX77812_PHASE31_CPU_I2C_ADDR 0x31 +#define MAX77812_PHASE211_CPU_I2C_ADDR 0x33 + +#define MAX77812_REG_RSET 0x00 +#define MAX77812_REG_INT_SRC 0x01 +#define MAX77812_REG_INT_SRC_M 0x02 +#define MAX77812_REG_TOPSYS_INT 0x03 +#define MAX77812_REG_TOPSYS_INT_M 0x04 +#define MAX77812_REG_TOPSYS_STAT 0x05 +#define MAX77812_REG_EN_CTRL 0x06 +#define MAX77812_EN_CTRL_EN_M4 BIT(6) +#define MAX77812_REG_STUP_DLY2 0x07 +#define MAX77812_REG_STUP_DLY3 0x08 +#define MAX77812_REG_STUP_DLY4 0x09 +#define MAX77812_REG_SHDN_DLY1 0x0A +#define MAX77812_REG_SHDN_DLY2 0x0B +#define MAX77812_REG_SHDN_DLY3 0x0C +#define MAX77812_REG_SHDN_DLY4 0x0D +#define MAX77812_REG_WDTRSTB_DEB 0x0E +#define MAX77812_REG_GPI_FUNC 0x0F +#define MAX77812_REG_GPI_DEB1 0x10 +#define MAX77812_REG_GPI_DEB2 0x11 +#define MAX77812_REG_GPI_PD_CTRL 0x12 +#define MAX77812_REG_PROT_CFG 0x13 +#define MAX77812_REG_VERSION 0x14 +#define MAX77812_REG_I2C_CFG 0x15 +#define MAX77812_REG_BUCK_INT 0x20 +#define MAX77812_REG_BUCK_INT_M 0x21 +#define MAX77812_REG_BUCK_STAT 0x22 +#define MAX77812_REG_M1_VOUT 0x23 +#define MAX77812_REG_M2_VOUT 0x24 +#define MAX77812_REG_M3_VOUT 0x25 +#define MAX77812_REG_M4_VOUT 0x26 +#define MAX77812_M4_VOUT_0_80V 0x6E +#define MAX77812_REG_M1_VOUT_D 0x27 +#define MAX77812_REG_M2_VOUT_D 0x28 +#define MAX77812_REG_M3_VOUT_D 0x29 +#define MAX77812_REG_M4_VOUT_D 0x2A +#define MAX77812_REG_M1_VOUT_S 0x2B +#define MAX77812_REG_M2_VOUT_S 0x2C +#define MAX77812_REG_M3_VOUT_S 0x2D +#define MAX77812_REG_M4_VOUT_S 0x2E +#define MAX77812_REG_M1_CFG 0x2F +#define MAX77812_REG_M2_CFG 0x30 +#define MAX77812_REG_M3_CFG 0x31 +#define MAX77812_REG_M4_CFG 0x32 +#define MAX77812_REG_GLB_CFG1 0x33 +#define MAX77812_REG_GLB_CFG2 0x34 +#define MAX77812_REG_GLB_CFG3 0x35 +#define MAX77812_REG_GLB_CFG4 0x36 +#define MAX77812_REG_GLB_CFG5 0x37 +#define MAX77812_REG_GLB_CFG6 0x38 +#define MAX77812_REG_GLB_CFG7 0x39 +#define MAX77812_REG_GLB_CFG8 0x3A +#define MAX77812_REG_PROT_ACCESS 0xFD +#define MAX77812_REG_MAX 0xFE + +#define MAX77812_REG_EN_CTRL_MASK(n) BIT(n) +#define MAX77812_START_SLEW_RATE_MASK 0x07 +#define MAX77812_SHDN_SLEW_RATE_MASK 0x70 +#define MAX77812_RAMPUP_SLEW_RATE_MASK 0x07 +#define MAX77812_RAMPDOWN_SLEW_RATE_MASK 0x70 +#define MAX77812_SLEW_RATE_SHIFT 4 + +#define MAX77812_OP_ACTIVE_DISCHARGE_MASK BIT(7) +#define MAX77812_PEAK_CURRENT_LMT_MASK 0x70 +#define MAX77812_SWITCH_FREQ_MASK 0x0C +#define MAX77812_FORCED_PWM_MASK BIT(1) +#define MAX77812_SLEW_RATE_CNTRL_MASK BIT(0) +#define MAX77812_START_SHD_DELAY_MASK 0x1F +#define MAX77812_VERSION_MASK 0x07 +#define MAX77812_ES2_VERSION 0x04 +#define MAX77812_QS_VERSION 0x05 + +#define MAX77812_VOUT_MASK 0xFF +#define MAX77812_VOUT_N_VOLTAGE 0xFF +#define MAX77812_VOUT_VMIN 250000 +#define MAX77812_VOUT_VMAX 1525000 +#define MAX77812_VOUT_STEP 5000 + +#endif diff --git a/bdk/power/regulator_5v.h b/bdk/power/regulator_5v.h index e916fbd..6bb837a 100644 --- a/bdk/power/regulator_5v.h +++ b/bdk/power/regulator_5v.h @@ -21,9 +21,9 @@ enum { - REGULATOR_5V_FAN = (1 << 0), - REGULATOR_5V_JC_R = (1 << 1), - REGULATOR_5V_JC_L = (1 << 2), + REGULATOR_5V_FAN = BIT(0), + REGULATOR_5V_JC_R = BIT(1), + REGULATOR_5V_JC_L = BIT(2), REGULATOR_5V_ALL = 0xFF }; diff --git a/bdk/rtc/max77620-rtc.h b/bdk/rtc/max77620-rtc.h index d9e216a..93b24c4 100644 --- a/bdk/rtc/max77620-rtc.h +++ b/bdk/rtc/max77620-rtc.h @@ -27,17 +27,17 @@ #define MAX77620_RTC_CONTROLM_REG 0x02 #define MAX77620_RTC_CONTROL_REG 0x03 -#define MAX77620_RTC_BIN_FORMAT (1 << 0) -#define MAX77620_RTC_24H (1 << 1) +#define MAX77620_RTC_BIN_FORMAT BIT(0) +#define MAX77620_RTC_24H BIT(1) #define MAX77620_RTC_UPDATE0_REG 0x04 -#define MAX77620_RTC_WRITE_UPDATE (1 << 0) -#define MAX77620_RTC_READ_UPDATE (1 << 4) +#define MAX77620_RTC_WRITE_UPDATE BIT(0) +#define MAX77620_RTC_READ_UPDATE BIT(4) #define MAX77620_RTC_SEC_REG 0x07 #define MAX77620_RTC_MIN_REG 0x08 #define MAX77620_RTC_HOUR_REG 0x09 -#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) +#define MAX77620_RTC_HOUR_PM_MASK BIT(6) #define MAX77620_RTC_WEEKDAY_REG 0x0A #define MAX77620_RTC_MONTH_REG 0x0B #define MAX77620_RTC_YEAR_REG 0x0C @@ -57,7 +57,7 @@ #define MAX77620_ALARM2_MONTH_REG 0x19 #define MAX77620_ALARM2_YEAR_REG 0x1A #define MAX77620_ALARM2_DATE_REG 0x1B -#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) +#define MAX77620_RTC_ALARM_EN_MASK BIT(7) typedef struct _rtc_time_t { u8 weekday; diff --git a/bdk/sec/se_t210.h b/bdk/sec/se_t210.h index 83557f7..0169869 100644 --- a/bdk/sec/se_t210.h +++ b/bdk/sec/se_t210.h @@ -47,15 +47,15 @@ #define ALG_RSA 4 #define ALG_NOP 0 #define ALG_AES_DEC 1 -#define SE_CONFIG_ENC_ALG(x) (x << SE_CONFIG_ENC_ALG_SHIFT) -#define SE_CONFIG_DEC_ALG(x) (x << SE_CONFIG_DEC_ALG_SHIFT) +#define SE_CONFIG_ENC_ALG(x) ((x) << SE_CONFIG_ENC_ALG_SHIFT) +#define SE_CONFIG_DEC_ALG(x) ((x) << SE_CONFIG_DEC_ALG_SHIFT) #define SE_CONFIG_DST_SHIFT 2 #define DST_MEMORY 0 #define DST_HASHREG 1 #define DST_KEYTAB 2 #define DST_SRK 3 #define DST_RSAREG 4 -#define SE_CONFIG_DST(x) (x << SE_CONFIG_DST_SHIFT) +#define SE_CONFIG_DST(x) ((x) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_ENC_MODE_SHIFT 24 #define SE_CONFIG_DEC_MODE_SHIFT 16 #define MODE_KEY128 0 @@ -66,57 +66,57 @@ #define MODE_SHA256 5 #define MODE_SHA384 6 #define MODE_SHA512 7 -#define SE_CONFIG_ENC_MODE(x) (x << SE_CONFIG_ENC_MODE_SHIFT) -#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT) +#define SE_CONFIG_ENC_MODE(x) ((x) << SE_CONFIG_ENC_MODE_SHIFT) +#define SE_CONFIG_DEC_MODE(x) ((x) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_RNG_CONFIG_REG_OFFSET 0x340 #define RNG_MODE_SHIFT 0 #define RNG_MODE_NORMAL 0 #define RNG_MODE_FORCE_INSTANTION 1 #define RNG_MODE_FORCE_RESEED 2 -#define SE_RNG_CONFIG_MODE(x) (x << RNG_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_CONFIG_SRC(x) ((x) << RNG_SRC_SHIFT) #define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344 #define RNG_SRC_RO_ENT_SHIFT 1 #define RNG_SRC_RO_ENT_ENABLE 1 #define RNG_SRC_RO_ENT_DISABLE 0 -#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT) +#define SE_RNG_SRC_CONFIG_ENT_SRC(x) ((x) << RNG_SRC_RO_ENT_SHIFT) #define RNG_SRC_RO_ENT_LOCK_SHIFT 0 #define RNG_SRC_RO_ENT_LOCK_ENABLE 1 #define RNG_SRC_RO_ENT_LOCK_DISABLE 0 -#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT) +#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) ((x) << RNG_SRC_RO_ENT_LOCK_SHIFT) #define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 #define SE_KEYTABLE_REG_OFFSET 0x31c #define SE_KEYTABLE_SLOT_SHIFT 4 -#define SE_KEYTABLE_SLOT(x) (x << SE_KEYTABLE_SLOT_SHIFT) +#define SE_KEYTABLE_SLOT(x) ((x) << SE_KEYTABLE_SLOT_SHIFT) #define SE_KEYTABLE_QUAD_SHIFT 2 #define QUAD_KEYS_128 0 #define QUAD_KEYS_192 1 #define QUAD_KEYS_256 1 #define QUAD_ORG_IV 2 #define QUAD_UPDTD_IV 3 -#define SE_KEYTABLE_QUAD(x) (x << SE_KEYTABLE_QUAD_SHIFT) +#define SE_KEYTABLE_QUAD(x) ((x) << SE_KEYTABLE_QUAD_SHIFT) #define SE_KEYTABLE_OP_TYPE_SHIFT 9 #define OP_READ 0 #define OP_WRITE 1 -#define SE_KEYTABLE_OP_TYPE(x) (x << SE_KEYTABLE_OP_TYPE_SHIFT) +#define SE_KEYTABLE_OP_TYPE(x) ((x) << SE_KEYTABLE_OP_TYPE_SHIFT) #define SE_KEYTABLE_TABLE_SEL_SHIFT 8 #define TABLE_KEYIV 0 #define TABLE_SCHEDULE 1 -#define SE_KEYTABLE_TABLE_SEL(x) (x << SE_KEYTABLE_TABLE_SEL_SHIFT) +#define SE_KEYTABLE_TABLE_SEL(x) ((x) << SE_KEYTABLE_TABLE_SEL_SHIFT) #define SE_KEYTABLE_PKT_SHIFT 0 -#define SE_KEYTABLE_PKT(x) (x << SE_KEYTABLE_PKT_SHIFT) +#define SE_KEYTABLE_PKT(x) ((x) << SE_KEYTABLE_PKT_SHIFT) #define SE_OP_DONE_SHIFT 4 #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 @@ -124,37 +124,37 @@ #define SE_CRYPTO_HASH_SHIFT 0 #define HASH_DISABLE 0 #define HASH_ENABLE 1 -#define SE_CRYPTO_HASH(x) (x << SE_CRYPTO_HASH_SHIFT) +#define SE_CRYPTO_HASH(x) ((x) << SE_CRYPTO_HASH_SHIFT) #define SE_CRYPTO_XOR_POS_SHIFT 1 #define XOR_BYPASS 0 #define XOR_TOP 2 #define XOR_BOTTOM 3 -#define SE_CRYPTO_XOR_POS(x) (x << SE_CRYPTO_XOR_POS_SHIFT) +#define SE_CRYPTO_XOR_POS(x) ((x) << SE_CRYPTO_XOR_POS_SHIFT) #define SE_CRYPTO_INPUT_SEL_SHIFT 3 #define INPUT_AHB 0 #define INPUT_RANDOM 1 #define INPUT_AESOUT 2 #define INPUT_LNR_CTR 3 -#define SE_CRYPTO_INPUT_SEL(x) (x << SE_CRYPTO_INPUT_SEL_SHIFT) +#define SE_CRYPTO_INPUT_SEL(x) ((x) << SE_CRYPTO_INPUT_SEL_SHIFT) #define SE_CRYPTO_VCTRAM_SEL_SHIFT 5 #define VCTRAM_AHB 0 #define VCTRAM_AESOUT 2 #define VCTRAM_PREVAHB 3 -#define SE_CRYPTO_VCTRAM_SEL(x) (x << SE_CRYPTO_VCTRAM_SEL_SHIFT) +#define SE_CRYPTO_VCTRAM_SEL(x) ((x) << SE_CRYPTO_VCTRAM_SEL_SHIFT) #define SE_CRYPTO_IV_SEL_SHIFT 7 #define IV_ORIGINAL 0 #define IV_UPDATED 1 -#define SE_CRYPTO_IV_SEL(x) (x << SE_CRYPTO_IV_SEL_SHIFT) +#define SE_CRYPTO_IV_SEL(x) ((x) << SE_CRYPTO_IV_SEL_SHIFT) #define SE_CRYPTO_CORE_SEL_SHIFT 8 #define CORE_DECRYPT 0 #define CORE_ENCRYPT 1 -#define SE_CRYPTO_CORE_SEL(x) (x << SE_CRYPTO_CORE_SEL_SHIFT) +#define SE_CRYPTO_CORE_SEL(x) ((x) << SE_CRYPTO_CORE_SEL_SHIFT) #define SE_CRYPTO_CTR_VAL_SHIFT 11 -#define SE_CRYPTO_CTR_VAL(x) (x << SE_CRYPTO_CTR_VAL_SHIFT) +#define SE_CRYPTO_CTR_VAL(x) ((x) << SE_CRYPTO_CTR_VAL_SHIFT) #define SE_CRYPTO_KEY_INDEX_SHIFT 24 -#define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT) +#define SE_CRYPTO_KEY_INDEX(x) ((x) << SE_CRYPTO_KEY_INDEX_SHIFT) #define SE_CRYPTO_CTR_CNTN_SHIFT 11 -#define SE_CRYPTO_CTR_CNTN(x) (x << SE_CRYPTO_CTR_CNTN_SHIFT) +#define SE_CRYPTO_CTR_CNTN(x) ((x) << SE_CRYPTO_CTR_CNTN_SHIFT) #define SE_CRYPTO_CTR_REG_COUNT 4 #define SE_CRYPTO_CTR_REG_OFFSET 0x308 @@ -166,7 +166,7 @@ #define OP_RESTART 2 #define OP_CTX_SAVE 3 #define OP_RESTART_IN 4 -#define SE_OPERATION(x) (x << SE_OPERATION_SHIFT) +#define SE_OPERATION(x) ((x) << SE_OPERATION_SHIFT) #define SE_CONTEXT_SAVE_CONFIG_REG_OFFSET 0x070 #define SE_CONTEXT_SAVE_WORD_QUAD_SHIFT 0 @@ -174,16 +174,16 @@ #define KEYS_4_7 1 #define ORIG_IV 2 #define UPD_IV 3 -#define SE_CONTEXT_SAVE_WORD_QUAD(x) (x << SE_CONTEXT_SAVE_WORD_QUAD_SHIFT) +#define SE_CONTEXT_SAVE_WORD_QUAD(x) ((x) << SE_CONTEXT_SAVE_WORD_QUAD_SHIFT) #define SE_CONTEXT_SAVE_KEY_INDEX_SHIFT 8 -#define SE_CONTEXT_SAVE_KEY_INDEX(x) (x << SE_CONTEXT_SAVE_KEY_INDEX_SHIFT) +#define SE_CONTEXT_SAVE_KEY_INDEX(x) ((x) << SE_CONTEXT_SAVE_KEY_INDEX_SHIFT) -#define SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT 24 +#define SE_CONTEXT_SAVE_STICKY_WORD_QUAD_SHIFT 24 #define STICKY_0_3 0 #define STICKY_4_7 1 #define SE_CONTEXT_SAVE_STICKY_WORD_QUAD(x) \ - (x << SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT) + ((x) << SE_CONTEXT_SAVE_STICKY_WORD_QUAD_SHIFT) #define SE_CONTEXT_SAVE_SRC_SHIFT 29 #define STICKY_BITS 0 @@ -193,15 +193,20 @@ #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(x) \ - (x << SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT) + ((x) << SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT) #define SE_CONTEXT_RSA_WORD_QUAD_SHIFT 12 #define SE_CONTEXT_RSA_WORD_QUAD(x) \ - (x << SE_CONTEXT_RSA_WORD_QUAD_SHIFT) + ((x) << SE_CONTEXT_RSA_WORD_QUAD_SHIFT) + +#define SE_CTX_SAVE_AUTO 0x074 +#define CTX_SAVE_AUTO_ENABLE BIT(0) +#define CTX_SAVE_AUTO_LOCK BIT(8) +#define CTX_SAVE_AUTO_CURR_CNT_MASK (0x3FF << 16) #define SE_INT_ENABLE_REG_OFFSET 0x00c #define SE_INT_STATUS_REG_OFFSET 0x010 @@ -210,9 +215,9 @@ #define INT_UNSET 0 #define INT_SET 1 #define SE_INT_OP_DONE_SHIFT 4 -#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT) +#define SE_INT_OP_DONE(x) ((x) << SE_INT_OP_DONE_SHIFT) #define SE_INT_ERROR_SHIFT 16 -#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT) +#define SE_INT_ERROR(x) ((x) << SE_INT_ERROR_SHIFT) #define SE_STATUS_0 0x800 #define SE_STATUS_0_STATE_WAIT_IN 3 @@ -223,10 +228,10 @@ #define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \ - (x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) + ((x) << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) #define SE_KEY_INDEX_SHIFT 8 -#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) (x << SE_KEY_INDEX_SHIFT) +#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) ((x) << SE_KEY_INDEX_SHIFT) #define SE_IN_LL_ADDR_REG_OFFSET 0x018 #define SE_OUT_LL_ADDR_REG_OFFSET 0x024 @@ -277,13 +282,13 @@ #define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 #define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 -#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) -#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) -#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) -#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) -#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) -#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) +#define SE_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG BIT(2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG BIT(3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG BIT(4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG BIT(5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG BIT(6) #define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F #define SE_KEY_READ_DISABLE_SHIFT 0 @@ -340,11 +345,11 @@ #define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 #define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 -#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) #define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG BIT(2) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT BIT(2) #define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 #define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F @@ -355,37 +360,37 @@ #define RSA_KEY_READ 0 #define RSA_KEY_WRITE 1 #define SE_RSA_KEY_OP_SHIFT 10 -#define SE_RSA_KEY_OP(x) (x << SE_RSA_KEY_OP_SHIFT) +#define SE_RSA_KEY_OP(x) ((x) << SE_RSA_KEY_OP_SHIFT) #define RSA_KEY_INPUT_MODE_REG 0 #define RSA_KEY_INPUT_MODE_DMA 1 #define RSA_KEY_INPUT_MODE_SHIFT 8 -#define RSA_KEY_INPUT_MODE(x) (x << RSA_KEY_INPUT_MODE_SHIFT) +#define RSA_KEY_INPUT_MODE(x) ((x) << RSA_KEY_INPUT_MODE_SHIFT) #define RSA_KEY_SLOT_ONE 0 #define RSA_KEY_SLOT_TW0 1 #define RSA_KEY_NUM_SHIFT 7 -#define RSA_KEY_NUM(x) (x << RSA_KEY_NUM_SHIFT) +#define RSA_KEY_NUM(x) ((x) << RSA_KEY_NUM_SHIFT) #define RSA_KEY_TYPE_EXP 0 #define RSA_KEY_TYPE_MOD 1 #define RSA_KEY_TYPE_SHIFT 6 -#define RSA_KEY_TYPE(x) (x << RSA_KEY_TYPE_SHIFT) +#define RSA_KEY_TYPE(x) ((x) << RSA_KEY_TYPE_SHIFT) #define SE_RSA_KEY_SIZE_REG_OFFSET 0x404 #define SE_RSA_EXP_SIZE_REG_OFFSET 0x408 #define RSA_KEY_SLOT_SHIFT 24 -#define RSA_KEY_SLOT(x) (x << RSA_KEY_SLOT_SHIFT) +#define RSA_KEY_SLOT(x) ((x) << RSA_KEY_SLOT_SHIFT) #define SE_RSA_CONFIG 0x400 #define RSA_KEY_PKT_WORD_ADDR_SHIFT 0 -#define RSA_KEY_PKT_WORD_ADDR(x) (x << RSA_KEY_PKT_WORD_ADDR_SHIFT) +#define RSA_KEY_PKT_WORD_ADDR(x) ((x) << RSA_KEY_PKT_WORD_ADDR_SHIFT) #define RSA_KEY_WORD_ADDR_SHIFT 0 -#define RSA_KEY_WORD_ADDR(x) (x << RSA_KEY_WORD_ADDR_SHIFT) +#define RSA_KEY_WORD_ADDR(x) ((x) << RSA_KEY_WORD_ADDR_SHIFT) #define SE_RSA_KEYTABLE_PKT_SHIFT 0 -#define SE_RSA_KEYTABLE_PKT(x) (x << SE_RSA_KEYTABLE_PKT_SHIFT) +#define SE_RSA_KEYTABLE_PKT(x) ((x) << SE_RSA_KEYTABLE_PKT_SHIFT) #endif /* _CRYPTO_TEGRA_SE_H */ diff --git a/bdk/sec/tsec_t210.h b/bdk/sec/tsec_t210.h index befe269..889d0d4 100644 --- a/bdk/sec/tsec_t210.h +++ b/bdk/sec/tsec_t210.h @@ -20,30 +20,30 @@ #define TSEC_BOOTKEYVER 0x1040 #define TSEC_STATUS 0x1044 #define TSEC_ITFEN 0x1048 -#define TSEC_ITFEN_CTXEN (1 << 0) -#define TSEC_ITFEN_MTHDEN (1 << 1) +#define TSEC_ITFEN_CTXEN BIT(0) +#define TSEC_ITFEN_MTHDEN BIT(1) #define TSEC_IRQMSET 0x1010 -#define TSEC_IRQMSET_WDTMR (1 << 1) -#define TSEC_IRQMSET_HALT (1 << 4) -#define TSEC_IRQMSET_EXTERR (1 << 5) -#define TSEC_IRQMSET_SWGEN0 (1 << 6) -#define TSEC_IRQMSET_SWGEN1 (1 << 7) +#define TSEC_IRQMSET_WDTMR BIT(1) +#define TSEC_IRQMSET_HALT BIT(4) +#define TSEC_IRQMSET_EXTERR BIT(5) +#define TSEC_IRQMSET_SWGEN0 BIT(6) +#define TSEC_IRQMSET_SWGEN1 BIT(7) #define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8) #define TSEC_IRQDEST 0x101C -#define TSEC_IRQDEST_HALT (1 << 4) -#define TSEC_IRQDEST_EXTERR (1 << 5) -#define TSEC_IRQDEST_SWGEN0 (1 << 6) -#define TSEC_IRQDEST_SWGEN1 (1 << 7) +#define TSEC_IRQDEST_HALT BIT(4) +#define TSEC_IRQDEST_EXTERR BIT(5) +#define TSEC_IRQDEST_SWGEN0 BIT(6) +#define TSEC_IRQDEST_SWGEN1 BIT(7) #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_CPUCTL 0x1100 -#define TSEC_CPUCTL_STARTCPU (1 << 1) +#define TSEC_CPUCTL_STARTCPU BIT(1) #define TSEC_BOOTVEC 0x1104 #define TSEC_DMACTL 0x110C #define TSEC_DMATRFBASE 0x1110 #define TSEC_DMATRFMOFFS 0x1114 #define TSEC_DMATRFCMD 0x1118 -#define TSEC_DMATRFCMD_IDLE (1 << 1) -#define TSEC_DMATRFCMD_IMEM (1 << 4) +#define TSEC_DMATRFCMD_IDLE BIT(1) +#define TSEC_DMATRFCMD_IMEM BIT(4) #define TSEC_DMATRFCMD_SIZE_256B (6 << 8) #define TSEC_DMATRFFBOFFS 0x111C diff --git a/bdk/soc/bpmp.c b/bdk/soc/bpmp.c index 1a8a205..2e1819d 100644 --- a/bdk/soc/bpmp.c +++ b/bdk/soc/bpmp.c @@ -25,38 +25,38 @@ #define BPMP_MMU_CACHE_LINE_SIZE 0x20 #define BPMP_CACHE_CONFIG 0x0 -#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_NEVER_ALLOCATE (1 << 6) -#define CFG_ENABLE_INTERRUPT (1 << 7) -#define CFG_MMU_TAG_MODE(x) (x << 8) +#define CFG_ENABLE_CACHE BIT(0) +#define CFG_ENABLE_SKEW_ASSOC BIT(1) +#define CFG_DISABLE_RANDOM_ALLOC BIT(2) +#define CFG_FORCE_WRITE_THROUGH BIT(3) +#define CFG_NEVER_ALLOCATE BIT(6) +#define CFG_ENABLE_INTERRUPT BIT(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_READ_BUFFER (1 << 11) -#define CFG_ENABLE_HANG_DETECT (1 << 12) -#define CFG_FULL_LINE_DIRTY (1 << 13) -#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 CFG_DISABLE_WRITE_BUFFER BIT(10) +#define CFG_DISABLE_READ_BUFFER BIT(11) +#define CFG_ENABLE_HANG_DETECT BIT(12) +#define CFG_FULL_LINE_DIRTY BIT(13) +#define CFG_TAG_CHK_ABRT_ON_ERR BIT(14) +#define CFG_TAG_CHK_CLR_ERR BIT(15) +#define CFG_DISABLE_SAMELINE BIT(16) +#define CFG_OBS_BUS_EN BIT(31) #define BPMP_CACHE_LOCK 0x4 -#define LOCK_LINE(x) (1 << x) +#define LOCK_LINE(x) BIT((x)) #define BPMP_CACHE_SIZE 0xC #define BPMP_CACHE_LFSR 0x10 #define BPMP_CACHE_TAG_STATUS 0x14 -#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0) +#define TAG_STATUS_TAG_CHECK_ERROR BIT(0) #define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0 #define BPMP_CACHE_CLKEN_OVERRIDE 0x18 -#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0) -#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1) +#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN BIT(0) +#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN BIT(1) #define BPMP_CACHE_MAINT_ADDR 0x20 #define BPMP_CACHE_MAINT_DATA 0x24 @@ -68,8 +68,8 @@ #define BPMP_CACHE_INT_CLEAR 0x44 #define BPMP_CACHE_INT_RAW_EVENT 0x48 #define BPMP_CACHE_INT_STATUS 0x4C -#define INT_MAINT_DONE (1 << 0) -#define INT_MAINT_ERROR (1 << 1) +#define INT_MAINT_DONE BIT(0) +#define INT_MAINT_ERROR BIT(1) #define BPMP_CACHE_RB_CFG 0x80 #define BPMP_CACHE_WB_CFG 0x84 @@ -78,12 +78,12 @@ #define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 #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_TLB_EN (1 << 2) -#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3) -#define MMU_CFG_ABORT_STORE_LAST (1 << 4) -#define MMU_CFG_CLR_ABORT (1 << 5) +#define MMU_CFG_BLOCK_MAIN_ENTRY_WR BIT(0) +#define MMU_CFG_SEQ_EN BIT(1) +#define MMU_CFG_TLB_EN BIT(2) +#define MMU_CFG_SEG_CHECK_ALL_ENTRIES BIT(3) +#define MMU_CFG_ABORT_STORE_LAST BIT(4) +#define MMU_CFG_CLR_ABORT BIT(5) #define BPMP_CACHE_MMU_CMD 0xB0 #define MMU_CMD_NOP 0 @@ -98,25 +98,25 @@ #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_OVERLAP BIT(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 ABORT_STAT_SEQ BIT(20) +#define ABORT_STAT_PROT BIT(21) #define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 #define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC #define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) #define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) -#define MMU_EN_CACHED (1 << 0) -#define MMU_EN_EXEC (1 << 1) -#define MMU_EN_READ (1 << 2) -#define MMU_EN_WRITE (1 << 3) +#define MMU_EN_CACHED BIT(0) +#define MMU_EN_EXEC BIT(1) +#define MMU_EN_READ BIT(2) +#define MMU_EN_WRITE BIT(3) bpmp_mmu_entry_t mmu_entries[] = { @@ -153,7 +153,7 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); 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) |= BIT(idx); if (apply) BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; @@ -172,7 +172,7 @@ void bpmp_mmu_enable() // Init BPMP MMU entries. BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0; - for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++) + for (u32 idx = 0; idx < ARRAY_SIZE(mmu_entries); idx++) bpmp_mmu_set_entry(idx, &mmu_entries[idx], false); BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; diff --git a/bdk/soc/ccplex.c b/bdk/soc/ccplex.c index 24a4787..a8d782d 100644 --- a/bdk/soc/ccplex.c +++ b/bdk/soc/ccplex.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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, @@ -15,18 +16,21 @@ */ #include +#include +#include #include #include -#include #include #include #include #include +#include +#include -void _ccplex_enable_power() +void _ccplex_enable_power_t210() { u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~BIT(5)); // Disable GPIO5 pinmuxing. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); // Enable cores power. @@ -40,37 +44,12 @@ void _ccplex_enable_power() i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); } -int _ccplex_pmc_enable_partition(u32 part, int enable) +void _ccplex_enable_power_t210b01() { - u32 part_mask = 1 << part; - u32 desired_state = enable << part; - - // Check if the partition has the state we want. - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - return 1; - - u32 i = 5001; - while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) - { - usleep(1); - i--; - if (i < 1) - return 0; - } - - // Toggle power gating. - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; - - i = 5001; - while (i > 0) - { - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - break; - usleep(1); - i--; - } - - return 1; + u8 pmic_cpu_addr = !(FUSE(FUSE_RESERVED_ODM28) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR; + u8 tmp = i2c_recv_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_EN_CTRL); + i2c_send_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_EN_CTRL, tmp | MAX77812_EN_CTRL_EN_M4); + i2c_send_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_M4_VOUT, MAX77812_M4_VOUT_0_80V); } void ccplex_boot_cpu0(u32 entry) @@ -78,7 +57,10 @@ void ccplex_boot_cpu0(u32 entry) // Set ACTIVE_CLUSER to FAST. FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; - _ccplex_enable_power(); + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + _ccplex_enable_power_t210(); + else + _ccplex_enable_power_t210b01(); if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. { @@ -94,12 +76,12 @@ void ccplex_boot_cpu0(u32 entry) // Configure MSELECT source and enable clock. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & 0xFFFFFFF7) | 8; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & ~BIT(CLK_V_MSELECT)) | BIT(CLK_V_MSELECT); // Configure initial CPU clock frequency and enable clock. CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = 1; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_CPUG); clock_enable_coresight(); @@ -107,11 +89,11 @@ void ccplex_boot_cpu0(u32 entry) CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; // Enable CPU rail. - _ccplex_pmc_enable_partition(0, 1); - // Enable cluster 0 non-CPU. - _ccplex_pmc_enable_partition(15, 1); - // Enable CE0. - _ccplex_pmc_enable_partition(14, 1); + pmc_enable_partition(0, 1); + // Enable cluster 0 non-CPU rail. + pmc_enable_partition(15, 1); + // Enable CE0 rail. + pmc_enable_partition(14, 1); // Request and wait for RAM repair. FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; @@ -131,7 +113,7 @@ void ccplex_boot_cpu0(u32 entry) // MC(MC_TZ_SECURITY_CTRL) = 1; // Clear MSELECT reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= ~BIT(CLK_V_MSELECT); // Clear NONCPU reset. CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; // Clear CPU0 reset. diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c index 41e69a2..cf0007e 100644 --- a/bdk/soc/clock.c +++ b/bdk/soc/clock.c @@ -16,110 +16,101 @@ */ #include +#include #include #include #include -/* - * 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 */ static const clock_t _clock_uart[] = { -/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, -/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, -/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, -/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, -/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, CLK_L_UARTA, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, CLK_L_UARTB, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, CLK_H_UARTC, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, CLK_U_UARTD, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, CLK_Y_UARTAPE, 0, 2 } }; //I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. 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 -/* 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 -/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz -/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz -/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_L_I2C1, 0, 19 }, //20.4MHz -> 100KHz + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_H_I2C2, 0, 4 }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_U_I2C3, 0, 4 }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_V_I2C4, 0, 19 }, //20.4MHz -> 100KHz + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_H_I2C5, 0, 4 }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_X_I2C6, 0, 19 } //20.4MHz -> 100KHz }; static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, 0 }; static clock_t _clock_tzram = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, CLK_V_TZRAM, 0, 0 }; static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, 3 }; static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, 2 }; static clock_t _clock_sor_safe = { - CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, CLK_Y_SOR_SAFE, 0, 0 }; static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, CLK_X_SOR0, 0, 0 }; static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, 2 }; static clock_t _clock_kfuse = { - CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_KFUSE, 0, 0 }; static clock_t _clock_cl_dvfs = { - CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, CLK_W_DVFS, 0, 0 }; static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, 4 }; static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 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, CLK_L_PWM, 6, 4 // Fref: 6.4MHz. Stock PLLP / 54: 7.55MHz. }; 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 + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_Y_SDMMC_LEGACY_TM, 4, 66 }; void clock_enable(const clock_t *clk) { // Put clock into reset. - CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); // Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); + CLOCK(clk->enable) &= ~BIT(clk->index); // Configure clock source if required. if (clk->source) CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); // Enable. - CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); + CLOCK(clk->enable) = (CLOCK(clk->enable) & ~BIT(clk->index)) | BIT(clk->index); usleep(2); // Take clock off reset. - CLOCK(clk->reset) &= ~(1 << clk->index); + CLOCK(clk->reset) &= ~BIT(clk->index); } void clock_disable(const clock_t *clk) { // Put clock into reset. - CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); // Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); + CLOCK(clk->enable) &= ~BIT(clk->index); } void clock_enable_fuse(bool enable) { + // Enable Fuse registers visibility. CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28); } @@ -133,7 +124,7 @@ void clock_disable_uart(u32 idx) clock_disable(&_clock_uart[idx]); } -#define UART_SRC_CLK_DIV_EN (1 << 24) +#define UART_SRC_CLK_DIV_EN BIT(24) int clock_uart_use_src_div(u32 idx, u32 baud) { @@ -164,6 +155,10 @@ void clock_disable_i2c(u32 idx) void clock_enable_se() { clock_enable(&_clock_se); + + // Lock clock to always enabled if T210B01. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SE) |= 0x100; } void clock_enable_tzram() @@ -223,12 +218,12 @@ void clock_disable_sor1() void clock_enable_kfuse() { - //clock_enable(&_clock_kfuse); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100; + u32 kfuse_clk_unmask = ~BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & kfuse_clk_unmask) | BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= kfuse_clk_unmask; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & kfuse_clk_unmask) | BIT(CLK_H_KFUSE); usleep(10); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= kfuse_clk_unmask; usleep(20); } @@ -281,7 +276,7 @@ void clock_enable_pllc(u32 divn) 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_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; usleep(10); @@ -294,7 +289,7 @@ void clock_enable_pllc(u32 divn) ; // Disable PLLC_OUT1, enable reset and set div to 1.5. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8); + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = BIT(8); // Enable PLLC_OUT1 and bring it out of reset. CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); @@ -304,15 +299,15 @@ void clock_enable_pllc(u32 divn) 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_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; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET; usleep(10); } -#define PLLC4_ENABLED (1 << 31) +#define PLLC4_ENABLED BIT(31) #define PLLC4_IN_USE (~PLLC4_ENABLED) u32 pllc4_enabled = 0; @@ -362,48 +357,60 @@ static void _clock_disable_pllc4(u32 mask) pllc4_enabled = 0; } -#define L_SWR_SDMMC1_RST (1 << 14) -#define L_SWR_SDMMC2_RST (1 << 9) -#define L_SWR_SDMMC4_RST (1 << 15) -#define U_SWR_SDMMC3_RST (1 << 5) +void clock_enable_pllu() +{ + // Configure PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) |= BIT(29); // Disable reference clock. + u32 pllu_cfg = (CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & 0xFFE00000) | BIT(24) | (1 << 16) | (0x19 << 8) | 2; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | PLLCX_BASE_ENABLE; // Enable. -#define L_CLK_ENB_SDMMC1 (1 << 14) -#define L_CLK_ENB_SDMMC2 (1 << 9) -#define L_CLK_ENB_SDMMC4 (1 << 15) -#define U_CLK_ENB_SDMMC3 (1 << 5) + // Wait for PLL to stabilize. + u32 timeout = (u32)TMR(TIMERUS_CNTR_1US) + 1300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & PLLCX_BASE_LOCK)) // PLL_LOCK. + if ((u32)TMR(TIMERUS_CNTR_1US) > timeout) + break; + usleep(10); -#define L_SET_SDMMC1_RST (1 << 14) -#define L_SET_SDMMC2_RST (1 << 9) -#define L_SET_SDMMC4_RST (1 << 15) -#define U_SET_SDMMC3_RST (1 << 5) + // Enable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) |= 0x2E00000; +} -#define L_CLR_SDMMC1_RST (1 << 14) -#define L_CLR_SDMMC2_RST (1 << 9) -#define L_CLR_SDMMC4_RST (1 << 15) -#define U_CLR_SDMMC3_RST (1 << 5) +void clock_disable_pllu() +{ + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x40000000; // Disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~0x20000000; // Enable reference clock. +} -#define L_SET_CLK_ENB_SDMMC1 (1 << 14) -#define L_SET_CLK_ENB_SDMMC2 (1 << 9) -#define L_SET_CLK_ENB_SDMMC4 (1 << 15) -#define U_SET_CLK_ENB_SDMMC3 (1 << 5) +void clock_enable_utmipll() +{ + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | (25 << 16) | (1 << 8); // 38.4Mhz * (25 / 1) = 960 MHz. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | (24 << 18); // Set delay count for 38.4Mhz osc crystal. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) & 0x7FFA000) | (1 << 15) | 375; -#define L_CLR_CLK_ENB_SDMMC1 (1 << 14) -#define L_CLR_CLK_ENB_SDMMC2 (1 << 9) -#define L_CLR_CLK_ENB_SDMMC4 (1 << 15) -#define U_CLR_CLK_ENB_SDMMC3 (1 << 5) + // Wait for UTMIPLL to stabilize. + u32 retries = 10; // Wait 20us + while (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & UTMIPLL_LOCK) && retries) + { + usleep(1); + retries--; + } +} static int _clock_sdmmc_is_reset(u32 id) { switch (id) { case SDMMC_1: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC1_RST; + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC1); case SDMMC_2: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC2_RST; + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC2); case SDMMC_3: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & U_SWR_SDMMC3_RST; + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & BIT(CLK_U_SDMMC3); case SDMMC_4: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC4_RST; + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC4); } return 0; } @@ -413,16 +420,16 @@ static void _clock_sdmmc_set_reset(u32 id) switch (id) { case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC1); break; case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC2); break; case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_SDMMC3); break; case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC4); break; } } @@ -432,16 +439,16 @@ static void _clock_sdmmc_clear_reset(u32 id) switch (id) { case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC1); break; case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC2); break; case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_SDMMC3); break; case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC4); break; } } @@ -451,13 +458,13 @@ static int _clock_sdmmc_is_enabled(u32 id) switch (id) { case SDMMC_1: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC1; + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC1); case SDMMC_2: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC2; + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC2); case SDMMC_3: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & U_CLK_ENB_SDMMC3; + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & BIT(CLK_U_SDMMC3); case SDMMC_4: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC4; + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC4); } return 0; } @@ -467,16 +474,16 @@ static void _clock_sdmmc_set_enable(u32 id) switch (id) { case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC1); break; case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC2); break; case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_SDMMC3); break; case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC4); break; } } @@ -486,16 +493,16 @@ static void _clock_sdmmc_clear_enable(u32 id) switch (id) { case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC1); break; case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC2); break; case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_SDMMC3); break; case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC4); break; } } @@ -503,7 +510,7 @@ static void _clock_sdmmc_clear_enable(u32 id) static void _clock_sdmmc_config_legacy_tm() { clock_t *clk = &_clock_sdmmc_legacy_tm; - if (!(CLOCK(clk->enable) & (1 << clk->index))) + if (!(CLOCK(clk->enable) & BIT(clk->index))) clock_enable(clk); } @@ -588,7 +595,7 @@ static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) // Enable PLLC4 if in use by any SDMMC. if (source) - _clock_enable_pllc4(1 << id); + _clock_enable_pllc4(BIT(id)); // Set SDMMC legacy timeout clock. _clock_sdmmc_config_legacy_tm(); @@ -680,7 +687,7 @@ void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) *pclock = 40800; *pdivisor = 1; break; - case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz. + case SDHCI_TIMING_MMC_HS102: // Actual IO Freq: 99.84 MHz. *pclock = 200000; *pdivisor = 2; break; @@ -712,5 +719,5 @@ void clock_sdmmc_disable(u32 id) _clock_sdmmc_set_reset(id); _clock_sdmmc_clear_enable(id); _clock_sdmmc_is_reset(id); - _clock_disable_pllc4(1 << id); + _clock_disable_pllc4(BIT(id)); } diff --git a/bdk/soc/clock.h b/bdk/soc/clock.h index bbcd482..2f6de41 100644 --- a/bdk/soc/clock.h +++ b/bdk/soc/clock.h @@ -48,6 +48,7 @@ #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_OUTA 0xC4 #define CLK_RST_CONTROLLER_PLLU_MISC 0xCC #define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 #define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 @@ -131,6 +132,7 @@ #define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 #define CLK_RST_CONTROLLER_PLLE_AUX 0x48C #define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG3 0x4C0 #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 @@ -140,6 +142,9 @@ #define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 #define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608 +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610 #define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 @@ -153,23 +158,288 @@ #define CLK_NO_SOURCE 0x0 /*! PLL control and status bits */ -#define PLLCX_BASE_ENABLE (1 << 30) -#define PLLCX_BASE_REF_DIS (1 << 29) -#define PLLCX_BASE_LOCK (1 << 27) +#define PLLCX_BASE_LOCK BIT(27) +#define PLLCX_BASE_REF_DIS BIT(29) +#define PLLCX_BASE_ENABLE BIT(30) -#define PLLA_BASE_IDDQ (1 << 25) -#define PLLA_OUT0_CLKEN (1 << 1) -#define PLLA_OUT0_RSTN_CLR (1 << 0) +#define PLLA_OUT0_RSTN_CLR BIT(0) +#define PLLA_OUT0_CLKEN BIT(1) +#define PLLA_BASE_IDDQ BIT(25) -#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 PLLC_OUT1_RSTN_CLR BIT(0) +#define PLLC_OUT1_CLKEN BIT(1) +#define PLLC_MISC1_IDDQ BIT(27) +#define PLLC_MISC_RESET BIT(30) -#define PLLC4_MISC_EN_LCKDET (1 << 30) -#define PLLC4_BASE_IDDQ (1 << 18) -#define PLLC4_OUT3_CLKEN (1 << 1) -#define PLLC4_OUT3_RSTN_CLR (1 << 0) +#define PLLC4_OUT3_RSTN_CLR BIT(0) +#define PLLC4_OUT3_CLKEN BIT(1) +#define PLLC4_BASE_IDDQ BIT(18) +#define PLLC4_MISC_EN_LCKDET BIT(30) + +#define UTMIPLL_LOCK BIT(31) + +/* + * CLOCK Peripherals: + * L 0 - 31 + * H 32 - 63 + * U 64 - 95 + * V 96 - 127 + * W 128 - 159 + * X 160 - 191 + * Y 192 - 223 + */ + +enum CLK_L_DEV +{ + CLK_L_CPU = 0, // Only reset. Deprecated. + CLK_L_BPMP = 1, // Only reset. + CLK_L_SYS = 2, // Only reset. + CLK_L_ISPB = 3, + CLK_L_RTC = 4, + CLK_L_TMR = 5, + CLK_L_UARTA = 6, + CLK_L_UARTB = 7, + CLK_L_GPIO = 8, + CLK_L_SDMMC2 = 9, + CLK_L_SPDIF = 10, + CLK_L_I2S2 = 11, // I2S1 + CLK_L_I2C1 = 12, + CLK_L_NDFLASH = 13, // HIDDEN. + CLK_L_SDMMC1 = 14, + CLK_L_SDMMC4 = 15, + CLK_L_TWC = 16, // HIDDEN. + CLK_L_PWM = 17, + CLK_L_I2S3 = 18, + CLK_L_EPP = 19, // HIDDEN. + CLK_L_VI = 20, + CLK_L_2D = 21, // HIDDEN. + CLK_L_USBD = 22, + CLK_L_ISP = 23, + CLK_L_3D = 24, // HIDDEN. + //CLK_L_ = 25, + CLK_L_DISP2 = 26, + CLK_L_DISP1 = 27, + CLK_L_HOST1X = 28, + CLK_L_VCP = 29, // HIDDEN. + CLK_L_I2S1 = 30, // I2S0 + CLK_L_BPMP_CACHE_CTRL = 31, // CONTROLLER +}; + +enum CLK_H_DEV +{ + CLK_H_MEM = 0, // MC. + CLK_H_AHBDMA = 1, + CLK_H_APBDMA = 2, + //CLK_H_ = 3, + CLK_H_KBC = 4, // HIDDEN. + CLK_H_STAT_MON = 5, + CLK_H_PMC = 6, + CLK_H_FUSE = 7, + CLK_H_KFUSE = 8, + CLK_H_SPI1 = 9, + CLK_H_SNOR = 10, // HIDDEN. + CLK_H_JTAG2TBC = 11, + CLK_H_SPI2 = 12, + CLK_H_XIO = 13, // HIDDEN. + CLK_H_SPI3 = 14, + CLK_H_I2C5 = 15, + CLK_H_DSI = 16, + //CLK_H_ = 17, + CLK_H_HSI = 18, // HIDDEN. + CLK_H_HDMI = 19, // HIDDEN. + CLK_H_CSI = 20, + //CLK_H_ = 21, + CLK_H_I2C2 = 22, + CLK_H_UARTC = 23, + CLK_H_MIPI_CAL = 24, + CLK_H_EMC = 25, + CLK_H_USB2 = 26, + CLK_H_USB3 = 27, // HIDDEN. + CLK_H_MPE = 28, // HIDDEN. + CLK_H_VDE = 29, // HIDDEN. + CLK_H_BSEA = 30, // HIDDEN. + CLK_H_BSEV = 31, +}; + +enum CLK_U_DEV +{ + //CLK_U_ = 0, + CLK_U_UARTD = 1, + CLK_U_UARTE = 2, // HIDDEN. + CLK_U_I2C3 = 3, + CLK_U_SPI4 = 4, + CLK_U_SDMMC3 = 5, + CLK_U_PCIE = 6, + CLK_U_UNUSED = 7, // RESERVED + CLK_U_AFI = 8, + CLK_U_CSITE = 9, + CLK_U_PCIEXCLK = 10, // Only reset. + CLK_U_BPMPUCQ = 11, // HIDDEN. + CLK_U_LA = 12, + CLK_U_TRACECLKIN = 13, // HIDDEN. + CLK_U_SOC_THERM = 14, + CLK_U_DTV = 15, + CLK_U_NAND_SPEED = 16, // HIDDEN. + CLK_U_I2C_SLOW = 17, + CLK_U_DSIB = 18, + CLK_U_TSEC = 19, + CLK_U_IRAMA = 20, + CLK_U_IRAMB = 21, + CLK_U_IRAMC = 22, + CLK_U_IRAMD = 23, // EMUCIF ON RESET + CLK_U_BPMP_CACHE_RAM = 24, + CLK_U_XUSB_HOST = 25, + CLK_U_CLK_M_DOUBLER = 26, + CLK_U_MSENC = 27, // HIDDEN. + CLK_U_SUS_OUT = 28, + CLK_U_DEV2_OUT = 29, + CLK_U_DEV1_OUT = 30, + CLK_U_XUSB_DEV = 31, +}; + +enum CLK_V_DEV +{ + CLK_V_CPUG = 0, + CLK_V_CPULP = 1, // Reserved. + CLK_V_3D2 = 2, // HIDDEN. + CLK_V_MSELECT = 3, + CLK_V_TSENSOR = 4, + CLK_V_I2S4 = 5, + CLK_V_I2S5 = 6, + CLK_V_I2C4 = 7, + CLK_V_SPI5 = 8, // HIDDEN. + CLK_V_SPI6 = 9, // HIDDEN. + CLK_V_AHUB = 10, // AUDIO. + CLK_V_APB2APE = 11, // APBIF. + CLK_V_DAM0 = 12, // HIDDEN. + CLK_V_DAM1 = 13, // HIDDEN. + CLK_V_DAM2 = 14, // HIDDEN. + CLK_V_HDA2CODEC_2X = 15, + CLK_V_ATOMICS = 16, + //CLK_V_ = 17, + //CLK_V_ = 18, + //CLK_V_ = 19, + //CLK_V_ = 20, + //CLK_V_ = 21, + CLK_V_SPDIF_DOUBLER = 22, + CLK_V_ACTMON = 23, + CLK_V_EXTPERIPH1 = 24, + CLK_V_EXTPERIPH2 = 25, + CLK_V_EXTPERIPH3 = 26, + CLK_V_SATA_OOB = 27, + CLK_V_SATA = 28, + CLK_V_HDA = 29, + CLK_V_TZRAM = 30, // HIDDEN. + CLK_V_SE = 31, // HIDDEN. +}; + +enum CLK_W_DEV +{ + CLK_W_HDA2HDMICODEC = 0, + CLK_W_RESERVED0 = 1, //satacoldrstn + CLK_W_PCIERX0 = 2, + CLK_W_PCIERX1 = 3, + CLK_W_PCIERX2 = 4, + CLK_W_PCIERX3 = 5, + CLK_W_PCIERX4 = 6, + CLK_W_PCIERX5 = 7, + CLK_W_CEC = 8, + CLK_W_PCIE2_IOBIST = 9, + CLK_W_EMC_IOBIST = 10, + CLK_W_HDMI_IOBIST = 11, // HIDDEN. + CLK_W_SATA_IOBIST = 12, + CLK_W_MIPI_IOBIST = 13, + CLK_W_XUSB_PADCTL = 14, // Only reset. + CLK_W_XUSB = 15, + CLK_W_CILAB = 16, + CLK_W_CILCD = 17, + CLK_W_CILEF = 18, + CLK_W_DSIA_LP = 19, + CLK_W_DSIB_LP = 20, + CLK_W_ENTROPY = 21, + CLK_W_DDS = 22, // HIDDEN. + //CLK_W_ = 23, + CLK_W_DP2 = 24, // HIDDEN. + CLK_W_AMX0 = 25, // HIDDEN. + CLK_W_ADX0 = 26, // HIDDEN. + CLK_W_DVFS = 27, + CLK_W_XUSB_SS = 28, + CLK_W_EMC_LATENCY = 29, + CLK_W_MC1 = 30, + //CLK_W_ = 31, +}; + +enum CLK_X_DEV +{ + CLK_X_SPARE = 0, + CLK_X_DMIC1 = 1, + CLK_X_DMIC2 = 2, + CLK_X_ETR = 3, + CLK_X_CAM_MCLK = 4, + CLK_X_CAM_MCLK2 = 5, + CLK_X_I2C6 = 6, + CLK_X_MC_CAPA = 7, // MC DAISY CHAIN1 + CLK_X_MC_CBPA = 8, // MC DAISY CHAIN2 + CLK_X_MC_CPU = 9, + CLK_X_MC_BBC = 10, + CLK_X_VIM2_CLK = 11, + //CLK_X_ = 12, + CLK_X_MIPIBIF = 13, //RESERVED + CLK_X_EMC_DLL = 14, + //CLK_X_ = 15, + CLK_X_HDMI_AUDIO = 16, // HIDDEN. + CLK_X_UART_FST_MIPI_CAL = 17, + CLK_X_VIC = 18, + //CLK_X_ = 19, + CLK_X_ADX1 = 20, // HIDDEN. + CLK_X_DPAUX = 21, + CLK_X_SOR0 = 22, + CLK_X_SOR1 = 23, + CLK_X_GPU = 24, + CLK_X_DBGAPB = 25, + CLK_X_HPLL_ADSP = 26, + CLK_X_PLLP_ADSP = 27, + CLK_X_PLLA_ADSP = 28, + CLK_X_PLLG_REF = 29, + //CLK_X_ = 30, + //CLK_X_ = 31, +}; + +enum CLK_Y_DEV +{ + CLK_Y_SPARE1 = 0, + CLK_Y_SDMMC_LEGACY_TM = 1, + CLK_Y_NVDEC = 2, + CLK_Y_NVJPG = 3, + CLK_Y_AXIAP = 4, + CLK_Y_DMIC3 = 5, + CLK_Y_APE = 6, + CLK_Y_ADSP = 7, + CLK_Y_MC_CDPA = 8, // MC DAISY CHAIN4 + CLK_Y_MC_CCPA = 9, // MC DAISY CHAIN3 + CLK_Y_MAUD = 10, + //CLK_Y_ = 11, + CLK_Y_SATA_USB_UPHY = 12, // Only reset. + CLK_Y_PEX_USB_UPHY = 13, // Only reset. + CLK_Y_TSECB = 14, + CLK_Y_DPAUX1 = 15, + CLK_Y_VI_I2C = 16, + CLK_Y_HSIC_TRK = 17, + CLK_Y_USB2_TRK = 18, + CLK_Y_QSPI = 19, + CLK_Y_UARTAPE = 20, + CLK_Y_ADSPINTF = 21, // Only reset. + CLK_Y_ADSPPERIPH = 22, // Only reset. + CLK_Y_ADSPDBG = 23, // Only reset. + CLK_Y_ADSPWDT = 24, // Only reset. + CLK_Y_ADSPSCU = 25, // Only reset. + CLK_Y_ADSPNEON = 26, + CLK_Y_NVENC = 27, + CLK_Y_IQC2 = 28, + CLK_Y_IQC1 = 29, + CLK_Y_SOR_SAFE = 30, + CLK_Y_PLLP_OUT_CPU = 31, +}; /*! Generic clock descriptor. */ typedef struct _clock_t @@ -215,6 +485,9 @@ void clock_enable_pwm(); void clock_disable_pwm(); void clock_enable_pllc(u32 divn); void clock_disable_pllc(); +void clock_enable_pllu(); +void clock_disable_pllu(); +void clock_enable_utmipll(); 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); diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index 84c366d..62dba31 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -20,9 +20,9 @@ #include #include +#include #include - -#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) +#include static const u32 evp_thunk_template[] = { 0xe92d0007, // STMFD SP!, {R0-R2} @@ -62,12 +62,48 @@ u32 fuse_read_odm(u32 idx) u32 fuse_read_odm_keygen_rev() { - if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) + bool has_new_keygen; + + // Check if it has new keygen. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + has_new_keygen = true; + else + has_new_keygen = (fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2; + + if (has_new_keygen) return (fuse_read_odm(2) & 0x1F); return 0; } +u32 fuse_read_hw_type() +{ + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + { + switch ((fuse_read_odm(4) & 0xF0000) >> 16) + { + case 1: + return FUSE_NX_HW_TYPE_IOWA; + case 2: + return FUSE_NX_HW_TYPE_HOAG; + } + } + + return FUSE_NX_HW_TYPE_ICOSA; +} + +u8 fuse_count_burnt(u32 val) +{ + u8 burnt_fuses = 0; + for (u32 i = 0; i < 32; i++) + { + if ((val >> i) & 1) + burnt_fuses++; + } + + return burnt_fuses; +} + void fuse_wait_idle() { u32 ctrl; @@ -87,7 +123,9 @@ u32 fuse_read(u32 addr) void fuse_read_array(u32 *words) { - for (u32 i = 0; i < 192; i++) + u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ? 256 : 192; + + for (u32 i = 0; i < array_size; i++) words[i] = fuse_read(i); } @@ -133,7 +171,7 @@ static int _patch_hash_one(u32 *word) { return 3; } - for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) + for (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++) { if (hash_vals[i] == hash) { @@ -222,7 +260,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) while (word_count) { total_read += word_count; - if (total_read >= ARRAYSIZE(words)) + if (total_read >= ARRAY_SIZE(words)) { break; } @@ -279,7 +317,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) while (word_count) { total_read += word_count; - if (total_read >= ARRAYSIZE(words)) + if (total_read >= ARRAY_SIZE(words)) { break; } @@ -328,8 +366,8 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) bool fuse_check_patched_rcm() { - // Check if XUSB in use. - if (FUSE(FUSE_RESERVED_SW) & (1<<7)) + // Check if XUSB in use or Tegra X1+. + if (FUSE(FUSE_RESERVED_SW) & (1<<7) || hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) return true; // Check if RCM is ipatched. diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h index e5ca2fb..d7d5c77 100644 --- a/bdk/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -64,6 +64,7 @@ #define FUSE_OPT_X_COORDINATE 0x214 #define FUSE_OPT_Y_COORDINATE 0x218 #define FUSE_GPU_IDDQ_CALIB 0x228 +#define FUSE_RESERVED_ODM28 0x240 #define FUSE_USB_CALIB_EXT 0x350 /*! Fuse commands. */ @@ -75,12 +76,21 @@ /*! Fuse cache registers. */ #define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) +enum +{ + FUSE_NX_HW_TYPE_ICOSA, + FUSE_NX_HW_TYPE_IOWA, + FUSE_NX_HW_TYPE_HOAG +}; + void fuse_disable_program(); -u32 fuse_read_odm(u32 idx); -u32 fuse_read_odm_keygen_rev(); +u32 fuse_read_odm(u32 idx); +u32 fuse_read_odm_keygen_rev(); +u32 fuse_read_hw_type(); +u8 fuse_count_burnt(u32 val); void fuse_wait_idle(); -int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); -int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); void fuse_read_array(u32 *words); bool fuse_check_patched_rcm(); diff --git a/bdk/soc/gpio.c b/bdk/soc/gpio.c index 281e867..5cd2ccd 100644 --- a/bdk/soc/gpio.c +++ b/bdk/soc/gpio.c @@ -18,23 +18,23 @@ #include #include -#define GPIO_BANK_IDX(port) (port >> 2) +#define GPIO_BANK_IDX(port) ((port) >> 2) -#define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_CNF_OFFSET(port) (0x00 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_OE_OFFSET(port) (0x10 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_OUT_OFFSET(port) (0x20 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_IN_OFFSET(port) (0x30 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_STA_OFFSET(port) (0x40 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_ENB_OFFSET(port) (0x50 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_LVL_OFFSET(port) (0x60 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_CLR_OFFSET(port) (0x70 + (((port) >> 2) << 8) + (((port) % 4) << 2)) -#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2)) -#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_OE_MASKED_OFFSET(port) (0x90 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) +#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_IRQ_BANK1 32 #define GPIO_IRQ_BANK2 33 diff --git a/bdk/soc/gpio.h b/bdk/soc/gpio.h index 99aed88..0c92b14 100644 --- a/bdk/soc/gpio.h +++ b/bdk/soc/gpio.h @@ -41,14 +41,14 @@ #define GPIO_ANY_EDGE_CHANGE 1 /*! GPIO pins (0-7 for each port). */ -#define GPIO_PIN_0 (1 << 0) -#define GPIO_PIN_1 (1 << 1) -#define GPIO_PIN_2 (1 << 2) -#define GPIO_PIN_3 (1 << 3) -#define GPIO_PIN_4 (1 << 4) -#define GPIO_PIN_5 (1 << 5) -#define GPIO_PIN_6 (1 << 6) -#define GPIO_PIN_7 (1 << 7) +#define GPIO_PIN_0 BIT(0) +#define GPIO_PIN_1 BIT(1) +#define GPIO_PIN_2 BIT(2) +#define GPIO_PIN_3 BIT(3) +#define GPIO_PIN_4 BIT(4) +#define GPIO_PIN_5 BIT(5) +#define GPIO_PIN_6 BIT(6) +#define GPIO_PIN_7 BIT(7) /*! GPIO ports (A-EE). */ #define GPIO_PORT_A 0 diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index 7b7ca04..dd79dc6 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -56,7 +56,15 @@ extern volatile nyx_storage_t *nyx_str; * PCLK - 68MHz init (-> 136MHz -> OC/4). */ -void _config_oscillators() +u32 hw_get_chip_id() +{ + if (((APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF) >= GP_HIDREV_MAJOR_T210B01) + return GP_HIDREV_MAJOR_T210B01; + else + return GP_HIDREV_MAJOR_T210; +} + +static void _config_oscillators() { CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. @@ -73,35 +81,44 @@ void _config_oscillators() PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set BPMP/SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set BPMP/SCLK source to Run and PLLP_OUT2 (204MHz). CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. } -void _config_gpios() +static void _config_gpios(bool nx_hoag) { - PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; - PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + // Clamp inputs when tristated. + APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; + + if (!nx_hoag) + { + PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + + // Set pin mode for UARTB/C TX pins. +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); +#endif +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); +#endif + + // Enable input logic for UARTB/C TX pins. + gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + } // Set Joy-Con IsAttached direction. PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; - // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. -#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B - gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); -#endif -#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C - gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); -#endif // Set Joy-Con IsAttached mode. gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); - // Enable input logic for Joy-Con IsAttached and UARTB/C TX pins. - gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); - gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + // Enable input logic for Joy-Con IsAttached pins. gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); @@ -120,27 +137,28 @@ void _config_gpios() // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); } -void _config_pmc_scratch() +static void _config_pmc_scratch() { - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; } -void _mbist_workaround() +static void _mbist_workaround() { - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + // Make sure Audio clocks are enabled before accessing I2S. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); // Set mux output to SOR1 clock switch. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; // Enabled PLLD and set csi to PLLD for test pattern generation. CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; - // Clear per-clock resets. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. + // Clear per-clock resets for APE/VIC/HOST1X/DISP1. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = BIT(CLK_X_VIC); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); usleep(2); // I2S channels to master and disable SLCG. @@ -159,20 +177,59 @@ void _mbist_workaround() VIC(0x8C) = 0xFFFFFFFF; usleep(2); - // Set per-clock reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC. + // Set per-clock reset for APE/VIC/HOST1X/DISP1. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC); // Enable specific clocks and disable all others. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. - //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep 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_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA. + // CLK L Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = + BIT(CLK_H_PMC) | + BIT(CLK_H_FUSE); + // CLK H Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = + BIT(CLK_L_RTC) | + BIT(CLK_L_TMR) | + BIT(CLK_L_GPIO) | + BIT(CLK_L_BPMP_CACHE_CTRL); + // CLK U Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = + BIT(CLK_U_CSITE) | + BIT(CLK_U_IRAMA) | + BIT(CLK_U_IRAMB) | + BIT(CLK_U_IRAMC) | + BIT(CLK_U_IRAMD) | + BIT(CLK_U_BPMP_CACHE_RAM); + // CLK V Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = + BIT(CLK_V_MSELECT) | + BIT(CLK_V_APB2APE) | + BIT(CLK_V_SPDIF_DOUBLER) | + BIT(CLK_V_SE); + // CLK W Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = + BIT(CLK_W_PCIERX0) | + BIT(CLK_W_PCIERX1) | + BIT(CLK_W_PCIERX2) | + BIT(CLK_W_PCIERX3) | + BIT(CLK_W_PCIERX4) | + BIT(CLK_W_PCIERX5) | + BIT(CLK_W_ENTROPY) | + BIT(CLK_W_MC1); + // CLK X Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = + BIT(CLK_X_MC_CAPA) | + BIT(CLK_X_MC_CBPA) | + BIT(CLK_X_MC_CPU) | + BIT(CLK_X_MC_BBC) | + BIT(CLK_X_GPU) | + BIT(CLK_X_DBGAPB) | + BIT(CLK_X_PLLG_REF); + // CLK Y Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = + BIT(CLK_Y_MC_CDPA) | + BIT(CLK_Y_MC_CCPA); // Disable clock gate overrides. CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; @@ -182,20 +239,21 @@ void _mbist_workaround() CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; // Set child clock sources. - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. } -void _config_se_brom() +static void _config_se_brom() { // Enable fuse clock. clock_enable_fuse(true); // Skip SBK/SSK if sept was run. - if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) + bool sbk_skip = b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN || FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; + if (!sbk_skip) { // Bootrom part we skipped. u32 sbk[4] = { @@ -225,115 +283,145 @@ void _config_se_brom() APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); } -void _config_regulators() +static void _config_regulators(bool tegra_t210) { // 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); + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); 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_ONOFFCNFG1, - (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + BIT(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, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - max77620_regulator_config_fps(REGULATOR_LDO4); - max77620_regulator_config_fps(REGULATOR_LDO8); - max77620_regulator_config_fps(REGULATOR_SD0); - max77620_regulator_config_fps(REGULATOR_SD1); - max77620_regulator_config_fps(REGULATOR_SD3); + if (tegra_t210) + { + // Configure all Flexible Power Sequencers for MAX77620. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + max77620_regulator_config_fps(REGULATOR_LDO4); + max77620_regulator_config_fps(REGULATOR_LDO8); + max77620_regulator_config_fps(REGULATOR_SD0); + max77620_regulator_config_fps(REGULATOR_SD1); + max77620_regulator_config_fps(REGULATOR_SD3); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, - (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, + (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ - // Set vdd_core voltage to 1.125V. - max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); + // Set vdd_core voltage to 1.125V. + max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); - // 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_GPIO6, 2); + // 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_GPIO6, 2); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + } + else // Tegra X1+ set vdd_core voltage to 1.05V. + max77620_regulator_set_voltage(REGULATOR_SD0, 1050000); } -void config_hw() +void hw_init() { + // Get Chip ID. + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + bool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG; + // Bootrom stuff we skipped by going through rcm. _config_se_brom(); //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; - _mbist_workaround(); + // Perform Memory Built-In Self Test WAR if T210. + if (tegra_t210) + _mbist_workaround(); + + // Enable Security Engine clock. clock_enable_se(); - // Enable fuse clock. + // Enable Fuse clock. clock_enable_fuse(true); - // Disable fuse programming. + // Disable Fuse programming. fuse_disable_program(); + // Enable clocks to Memory controllers and disable AHB redirect. mc_enable(); + // Initialize counters, CLKM, BPMP and other clocks based on 38.4MHz oscillator. _config_oscillators(); - APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; - _config_gpios(); + + // Initialize pin configuration. + _config_gpios(nx_hoag); #ifdef DEBUG_UART_PORT clock_enable_uart(DEBUG_UART_PORT); uart_init(DEBUG_UART_PORT, 115200); #endif + // Enable Dynamic Voltage and Frequency Scaling device clock. clock_enable_cl_dvfs(); + // Enable clocks to I2C1 and I2CPWR. clock_enable_i2c(I2C_1); clock_enable_i2c(I2C_5); + // Enable clock to TZRAM. clock_enable_tzram(); - i2c_init(I2C_1); + // Initialize I2C5, mandatory for PMIC. i2c_init(I2C_5); + //! TODO: Why? Device is NFC MCU on Lite. + if (nx_hoag) + max77620_regulator_set_volt_and_flags(REGULATOR_LDO8, 2800000, MAX77620_POWER_MODE_NORMAL); + + // Initialize I2C1 for various power related devices. + i2c_init(I2C_1); + // Enable charger in case it's disabled. bq24193_enable_charger(); - _config_regulators(); + // Initialize various regulators based on Erista/Mariko platform. + _config_regulators(tegra_t210); _config_pmc_scratch(); // Missing from 4.x+ - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). + // Set BPMP/SCLK to PLLP_OUT (408MHz). + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; + // Disable TZRAM shutdown control and lock the regs. + if (!tegra_t210) + { + PMC(APBDEV_PMC_TZRAM_PWR_CNTRL) &= 0xFFFFFFFE; + PMC(APBDEV_PMC_TZRAM_NON_SEC_DISABLE) = 3; + PMC(APBDEV_PMC_TZRAM_SEC_DISABLE) = 3; + } + + // Initialize External memory controller and configure DRAM parameters. sdram_init(); 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 hw_reinit_workaround(bool extra_reconfig, u32 magic) { // Disable BPMP max clock. bpmp_clk_rate_set(BPMP_CLK_NORMAL); @@ -354,8 +442,8 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) nyx_str->mtc_cfg.init_done = 0; // Re-enable clocks to Audio Processing Engine as a workaround to hanging. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); if (extra_reconfig) { @@ -377,7 +465,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) // Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits. if (magic == 0xBAADF00D) { - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_USBD); sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0); clock_disable_cl_dvfs(); diff --git a/bdk/soc/hw_init.h b/bdk/soc/hw_init.h index d19f271..ff9ae4a 100644 --- a/bdk/soc/hw_init.h +++ b/bdk/soc/hw_init.h @@ -20,7 +20,8 @@ #include -void config_hw(); -void reconfig_hw_workaround(bool extra_reconfig, u32 magic); +void hw_init(); +void hw_reinit_workaround(bool extra_reconfig, u32 magic); +u32 hw_get_chip_id(); #endif diff --git a/bdk/soc/i2c.c b/bdk/soc/i2c.c index d3f31e7..099a182 100644 --- a/bdk/soc/i2c.c +++ b/bdk/soc/i2c.c @@ -20,31 +20,98 @@ #include #include +#define I2C_PACKET_PROT_I2C BIT(4) +#define I2C_HEADER_CONT_XFER BIT(15) +#define I2C_HEADER_REP_START BIT(16) +#define I2C_HEADER_IE_ENABLE BIT(17) +#define I2C_HEADER_READ BIT(19) + +#define I2C_CNFG (0x00 / 4) +#define CMD1_WRITE (0 << 6) +#define CMD1_READ BIT(6) +#define NORMAL_MODE_GO BIT(9) +#define PACKET_MODE_GO BIT(10) +#define NEW_MASTER_FSM BIT(11) +#define DEBOUNCE_CNT_4T (2 << 12) + +#define I2C_CMD_ADDR0 (0x04 / 4) +#define ADDR0_WRITE 0 +#define ADDR0_READ 1 + +#define I2C_CMD_DATA1 (0x0C / 4) +#define I2C_CMD_DATA2 (0x10 / 4) + +#define I2C_STATUS (0x1C / 4) +#define I2C_STATUS_NOACK (0xF << 0) +#define I2C_STATUS_BUSY BIT(8) + +#define I2C_TX_FIFO (0x50 / 4) +#define I2C_RX_FIFO (0x54 / 4) + +#define I2C_FIFO_CONTROL (0x5C / 4) +#define RX_FIFO_FLUSH BIT(0) +#define TX_FIFO_FLUSH BIT(1) + +#define I2C_FIFO_STATUS (0x60 / 4) +#define RX_FIFO_FULL_CNT (0xF << 0) +#define TX_FIFO_EMPTY_CNT (0xF << 4) + +#define I2C_INT_EN (0x64 / 4) +#define I2C_INT_STATUS (0x68 / 4) +#define I2C_INT_SOURCE (0x70 / 4) +#define RX_FIFO_DATA_REQ BIT(0) +#define TX_FIFO_DATA_REQ BIT(1) +#define ARB_LOST BIT(2) +#define NO_ACK BIT(3) +#define RX_FIFO_UNDER BIT(4) +#define TX_FIFO_OVER BIT(5) +#define ALL_PACKETS_COMPLETE BIT(6) +#define PACKET_COMPLETE BIT(7) +#define BUS_CLEAR_DONE BIT(11) + +#define I2C_CLK_DIVISOR (0x6C / 4) + +#define I2C_BUS_CLEAR_CONFIG (0x84 / 4) +#define BC_ENABLE BIT(0) +#define BC_TERMINATE BIT(1) + +#define I2C_BUS_CLEAR_STATUS (0x88 / 4) + +#define I2C_CONFIG_LOAD (0x8C / 4) +#define MSTR_CONFIG_LOAD BIT(0) +#define TIMEOUT_CONFIG_LOAD BIT(2) + static const u32 i2c_addrs[] = { - 0x7000C000, 0x7000C400, 0x7000C500, - 0x7000C700, 0x7000D000, 0x7000D100 + 0x7000C000, // I2C_1. + 0x7000C400, // I2C_2. + 0x7000C500, // I2C_3. + 0x7000C700, // I2C_4. + 0x7000D000, // I2C_5. + 0x7000D100 // I2C_6. }; -static void _i2c_wait(vu32 *base) +static void _i2c_load_cfg_wait(vu32 *base) { - base[I2C_CONFIG_LOAD] = 0x25; + base[I2C_CONFIG_LOAD] = BIT(5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD; for (u32 i = 0; i < 20; i++) { usleep(1); - if (!(base[I2C_CONFIG_LOAD] & 1)) + if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD)) break; } } -static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) +static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size) { if (size > 8) return 0; u32 tmp = 0; - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). + vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; + + // Set device address and send mode. + base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE; if (size > 4) { @@ -60,44 +127,55 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) base[I2C_CMD_DATA1] = tmp; //Set value. } - base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. + // Set size and send mode. + base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE; - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + // Load configuration. + _i2c_load_cfg_wait(base); - u32 timeout = get_tmr_ms() + 1500; - while (base[I2C_STATUS] & 0x100) + // Initiate transaction on normal mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; + + u32 timeout = get_tmr_ms() + 400; // Actual for max 8 bytes at 100KHz is 0.74ms. + while (base[I2C_STATUS] & I2C_STATUS_BUSY) { if (get_tmr_ms() > timeout) return 0; } - if (base[I2C_STATUS] << 28) + if (base[I2C_STATUS] & I2C_STATUS_NOACK) return 0; return 1; } -static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) +static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) { if (size > 8) return 0; - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). - base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. - _i2c_wait(base); // Kick transaction. + vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + // Set device address and recv mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; - u32 timeout = get_tmr_ms() + 1500; - while (base[I2C_STATUS] & 0x100) + // Set size and recv mode. + base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on normal mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; + + u32 timeout = get_tmr_ms() + 400; // Actual for max 8 bytes at 100KHz is 0.74ms. + while (base[I2C_STATUS] & I2C_STATUS_BUSY) { if (get_tmr_ms() > timeout) return 0; } - if (base[I2C_STATUS] << 28) + if (base[I2C_STATUS] & I2C_STATUS_NOACK) return 0; u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. @@ -113,60 +191,234 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) return 1; } -void i2c_init(u32 idx) +static int _i2c_send_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) { - vu32 *base = (vu32 *)i2c_addrs[idx]; + if (size > 32) + return 0; - base[I2C_CLK_DIVISOR_REGISTER] = 0x50001; - base[I2C_BUS_CLEAR_CONFIG] = 0x90003; - _i2c_wait(base); + int res = 0; + + vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; + + // Enable interrupts. + base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | + ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | TX_FIFO_DATA_REQ; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; + + // Set device address and recv mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; + + // Set recv mode. + base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE; + + // Set and flush FIFO. + base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on packet mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO; + + u32 hdr[3]; + hdr[0] = I2C_PACKET_PROT_I2C; + hdr[1] = size - 1; + hdr[2] = I2C_HEADER_IE_ENABLE | I2C_HEADER_CONT_XFER | (dev_addr << 1); + + // Send header with request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + + u32 timeout = get_tmr_ms() + 400; + while (size) + { + if (base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT) + { + u32 tmp = 0; + u32 snd_size = MIN(size, 4); + memcpy(&tmp, buf, snd_size); + base[I2C_TX_FIFO] = tmp; + buf += snd_size; + size -= snd_size; + } + + if (get_tmr_ms() > timeout) + { + res = 1; + break; + } + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK) + res = 1; + + // Disable packet mode. + usleep(20); + base[I2C_CNFG] &= 0xFFFFF9FF; + + // Disable interrupts. + base[I2C_INT_EN] = 0; + + return res; +} + +static int _i2c_recv_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr, u32 reg) +{ + if (size > 32) + return 0; + + int res = 0; + + vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; + + // Enable interrupts. + base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | + ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | RX_FIFO_DATA_REQ; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; + + // Set device address and recv mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; + + // Set recv mode. + base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ; + + // Set and flush FIFO. + base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on packet mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO; + + // Send reg request. + u32 hdr[3]; + hdr[0] = I2C_PACKET_PROT_I2C; + hdr[1] = 1 - 1; + hdr[2] = I2C_HEADER_REP_START | (dev_addr << 1); + + // Send header with reg request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + base[I2C_TX_FIFO] = reg; + + u32 timeout = get_tmr_ms() + 400; + while (!(base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT)) + if (get_tmr_ms() > timeout) + break; + + // Send read request. + hdr[1] = size - 1; + hdr[2] = I2C_HEADER_READ | (dev_addr << 1); + + // Send header with read request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + + timeout = get_tmr_ms() + 400; + while (size) + { + if (base[I2C_FIFO_STATUS] & RX_FIFO_FULL_CNT) + { + u32 rcv_size = MIN(size, 4); + u32 tmp = base[I2C_RX_FIFO]; + memcpy(buf, &tmp, rcv_size); + buf += rcv_size; + size -= rcv_size; + } + + if (get_tmr_ms() > timeout) + { + res = 1; + break; + } + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK) + res = 1; + + // Disable packet mode. + usleep(20); + base[I2C_CNFG] &= 0xFFFFF9FF; + + // Disable interrupts. + base[I2C_INT_EN] = 0; + + return res; +} + +void i2c_init(u32 i2c_idx) +{ + vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; + + base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2. + base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE; + + // Load configuration. + _i2c_load_cfg_wait(base); for (u32 i = 0; i < 10; i++) { usleep(20000); - if (base[INTERRUPT_STATUS_REGISTER] & 0x800) + if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE) break; } (vu32)base[I2C_BUS_CLEAR_STATUS]; - base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER]; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; } -int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) +int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr) +{ + return _i2c_recv_single(i2c_idx, buf, size, dev_addr); +} + +int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size) +{ + if (size > 32) + return 0; + + return _i2c_send_pkt(i2c_idx, buf, size, dev_addr); +} + +int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg) +{ + return _i2c_recv_pkt(i2c_idx, buf, size, dev_addr, reg); +} + +int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size) { u8 tmp[4]; if (size > 7) return 0; - tmp[0] = y; + tmp[0] = reg; memcpy(tmp + 1, buf, size); - return _i2c_send_pkt(idx, x, tmp, size + 1); + return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1); } -int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x) +int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg) { - return _i2c_recv_pkt(idx, buf, size, x); -} - -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_single(i2c_idx, dev_addr, (u8 *)®, 1); if (res) - res = _i2c_recv_pkt(idx, buf, size, x); + res = _i2c_recv_single(i2c_idx, buf, size, dev_addr); return res; } -int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) +int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val) { - return i2c_send_buf_small(idx, x, y, &b, 1); + return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1); } -u8 i2c_recv_byte(u32 idx, u32 x, u32 y) +u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg) { u8 tmp = 0; - i2c_recv_buf_small(&tmp, 1, idx, x, y); + i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg); return tmp; } diff --git a/bdk/soc/i2c.h b/bdk/soc/i2c.h index a630b15..a04eec1 100644 --- a/bdk/soc/i2c.h +++ b/bdk/soc/i2c.h @@ -27,22 +27,13 @@ #define I2C_5 4 #define I2C_6 5 -#define I2C_CNFG 0x00 -#define I2C_CMD_ADDR0 0x01 -#define I2C_CMD_DATA1 0x03 -#define I2C_CMD_DATA2 0x04 -#define I2C_STATUS 0x07 -#define INTERRUPT_STATUS_REGISTER 0x1A -#define I2C_CLK_DIVISOR_REGISTER 0x1B -#define I2C_BUS_CLEAR_CONFIG 0x21 -#define I2C_BUS_CLEAR_STATUS 0x22 -#define I2C_CONFIG_LOAD 0x23 - -void i2c_init(u32 idx); -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_send_byte(u32 idx, u32 x, u32 y, u8 b); -u8 i2c_recv_byte(u32 idx, u32 x, u32 y); +void i2c_init(u32 i2c_idx); +int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr); +int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size); +int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg); +int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size); +int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg); +int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val); +u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg); #endif diff --git a/bdk/soc/irq.c b/bdk/soc/irq.c index cb34d12..4fb39ca 100644 --- a/bdk/soc/irq.c +++ b/bdk/soc/irq.c @@ -47,10 +47,10 @@ static void _irq_enable_source(u32 irq) u32 bit = irq % 32; // Set as normal IRQ. - ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~(1 << bit); + ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~BIT(bit); // Enable IRQ source. - ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = 1 << bit; + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = BIT(bit); } static void _irq_disable_source(u32 irq) @@ -59,7 +59,7 @@ static void _irq_disable_source(u32 irq) u32 bit = irq % 32; // Disable IRQ source. - ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = 1 << bit; + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = BIT(bit); } static void _irq_disable_and_ack_all() @@ -79,7 +79,7 @@ static void _irq_ack_source(u32 irq) u32 bit = irq % 32; // Force stop the interrupt as it's serviced here. - ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = 1 << bit; + ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = BIT(bit); } void irq_free(u32 irq) diff --git a/bdk/soc/irq.h b/bdk/soc/irq.h index d33ffbe..dbd5ee2 100644 --- a/bdk/soc/irq.h +++ b/bdk/soc/irq.h @@ -209,8 +209,8 @@ typedef enum _irq_status_t typedef enum _irq_flags_t { IRQ_FLAG_NONE = 0, - IRQ_FLAG_ONE_OFF = (1 << 0), - IRQ_FLAG_REPLACEABLE = (1 << 1) + IRQ_FLAG_ONE_OFF = BIT(0), + IRQ_FLAG_REPLACEABLE = BIT(1) } irq_flags_t; void irq_end(); diff --git a/bdk/soc/kfuse.h b/bdk/soc/kfuse.h index 099dcac..2cd290b 100644 --- a/bdk/soc/kfuse.h +++ b/bdk/soc/kfuse.h @@ -19,16 +19,16 @@ #include -#define KFUSE_STATE_SOFTRESET (1 << 31) -#define KFUSE_STATE_STOP (1 << 25) -#define KFUSE_STATE_RESTART (1 << 24) -#define KFUSE_STATE_CRCPASS (1 << 17) -#define KFUSE_STATE_DONE (1 << 16) -#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 -#define KFUSE_STATE_ERRBLOCK_SHIFT 8 #define KFUSE_STATE_CURBLOCK_MASK 0x3F +#define KFUSE_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_DONE BIT(16) +#define KFUSE_STATE_CRCPASS BIT(17) +#define KFUSE_STATE_RESTART BIT(24) +#define KFUSE_STATE_STOP BIT(25) +#define KFUSE_STATE_SOFTRESET BIT(31) -#define KFUSE_KEYADDR_AUTOINC (1<<16) +#define KFUSE_KEYADDR_AUTOINC BIT(16) #define KFUSE_STATE 0x80 #define KFUSE_KEYADDR 0x88 diff --git a/bdk/soc/pinmux.h b/bdk/soc/pinmux.h index 9a3ed5c..48fcab3 100644 --- a/bdk/soc/pinmux.h +++ b/bdk/soc/pinmux.h @@ -71,6 +71,18 @@ #define PINMUX_AUX_GPIO_PH6 0x250 #define PINMUX_AUX_GPIO_PK3 0x260 #define PINMUX_AUX_GPIO_PZ1 0x280 +/* Only in T210B01 */ +#define PINMUX_AUX_SDMMC2_DAT0 0x294 +#define PINMUX_AUX_SDMMC2_DAT1 0x298 +#define PINMUX_AUX_SDMMC2_DAT2 0x29C +#define PINMUX_AUX_SDMMC2_DAT3 0x2A0 +#define PINMUX_AUX_SDMMC2_DAT4 0x2A4 +#define PINMUX_AUX_SDMMC2_DAT5 0x2A8 +#define PINMUX_AUX_SDMMC2_DAT6 0x2AC +#define PINMUX_AUX_SDMMC2_DAT7 0x2B0 +#define PINMUX_AUX_SDMMC2_CLK 0x2B4 +#define PINMUX_AUX_SDMMC2_CMD 0x2BC + /*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ #define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) @@ -87,17 +99,18 @@ #define PINMUX_PULL_DOWN (1 << 2) #define PINMUX_PULL_UP (2 << 2) -#define PINMUX_TRISTATE (1 << 4) -#define PINMUX_PARKED (1 << 5) -#define PINMUX_INPUT_ENABLE (1 << 6) -#define PINMUX_LOCK (1 << 7) -#define PINMUX_LPDR (1 << 8) -#define PINMUX_HSM (1 << 9) +#define PINMUX_TRISTATE BIT(4) +#define PINMUX_PARKED BIT(5) +#define PINMUX_INPUT_ENABLE BIT(6) +#define PINMUX_LOCK BIT(7) +#define PINMUX_LPDR BIT(8) +#define PINMUX_HSM BIT(9) -#define PINMUX_IO_HV (1 << 10) -#define PINMUX_OPEN_DRAIN (1 << 11) -#define PINMUX_SCHMT (1 << 12) +#define PINMUX_IO_HV BIT(10) +#define PINMUX_OPEN_DRAIN BIT(11) +#define PINMUX_SCHMT BIT(12) +#define PINMUX_DRIVE_MASK (3 << 13) #define PINMUX_DRIVE_1X (0 << 13) #define PINMUX_DRIVE_2X (1 << 13) #define PINMUX_DRIVE_3X (2 << 13) diff --git a/bdk/soc/pmc.c b/bdk/soc/pmc.c new file mode 100644 index 0000000..62caa22 --- /dev/null +++ b/bdk/soc/pmc.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 . + */ + +#include +#include +#include + +int pmc_enable_partition(u32 part, int enable) +{ + u32 part_mask = BIT(part); + u32 desired_state = enable << part; + + // Check if the partition has the state we want. + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + return 1; + + u32 i = 5001; + while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) + { + usleep(1); + i--; + if (i < 1) + return 0; + } + + // Toggle power gating. + PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; + + i = 5001; + while (i > 0) + { + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + break; + usleep(1); + i--; + } + + return 1; +} diff --git a/bdk/soc/pmc.h b/bdk/soc/pmc.h index 7df7922..45fa034 100644 --- a/bdk/soc/pmc.h +++ b/bdk/soc/pmc.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk + * Copyright (c) 2018-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, @@ -18,41 +19,47 @@ #ifndef _PMC_H_ #define _PMC_H_ +#include + /*! PMC registers. */ #define APBDEV_PMC_CNTRL 0x0 -#define PMC_CNTRL_MAIN_RST (1 << 4) +#define PMC_CNTRL_MAIN_RST BIT(4) #define APBDEV_PMC_SEC_DISABLE 0x4 #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #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 BIT(12) +#define PMC_NO_IOPOWER_AUDIO_HV BIT(18) +#define PMC_NO_IOPOWER_GPIO_IO_EN BIT(21) #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 PMC_SCRATCH0_MODE_WARMBOOT BIT(0) +#define PMC_SCRATCH0_MODE_RCM BIT(1) +#define PMC_SCRATCH0_MODE_PAYLOAD BIT(29) +#define PMC_SCRATCH0_MODE_FASTBOOT BIT(30) +#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) +#define PMC_SCRATCH0_MODE_CUSTOM_ALL (PMC_SCRATCH0_MODE_RECOVERY | PMC_SCRATCH0_MODE_FASTBOOT | PMC_SCRATCH0_MODE_PAYLOAD) #define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 #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 BIT(12) +#define PMC_PWR_DET_AUDIO_HV BIT(18) +#define PMC_PWR_DET_GPIO_IO_EN BIT(21) #define APBDEV_PMC_DDR_PWR 0xE8 #define APBDEV_PMC_USB_AO 0xF0 #define APBDEV_PMC_CRYPTO_OP 0xF4 #define PMC_CRYPTO_OP_SE_ENABLE 0 #define PMC_CRYPTO_OP_SE_DISABLE 1 #define APBDEV_PMC_SCRATCH33 0x120 +#define APBDEV_PMC_SCRATCH37 0x130 +#define PMC_SCRATCH37_KERNEL_PANIC_FLAG BIT(24) #define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 #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 PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN BIT(2) #define APBDEV_PMC_RST_STATUS 0x1B4 #define APBDEV_PMC_IO_DPD_REQ 0x1B8 +#define PMC_IO_DPD_REQ_DPD_OFF BIT(30) #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 #define APBDEV_PMC_VDDP_SEL 0x1CC #define APBDEV_PMC_DDR_CFG 0x1D0 @@ -83,5 +90,10 @@ #define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH200 0x840 +#define APBDEV_PMC_TZRAM_PWR_CNTRL 0xBE8 +#define APBDEV_PMC_TZRAM_SEC_DISABLE 0xBEC +#define APBDEV_PMC_TZRAM_NON_SEC_DISABLE 0xBF0 + +int pmc_enable_partition(u32 part, int enable); #endif diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h index 78432c1..e48f53a 100644 --- a/bdk/soc/t210.h +++ b/bdk/soc/t210.h @@ -61,6 +61,9 @@ #define EMC_BASE 0x7001B000 #define EMC0_BASE 0x7001E000 #define EMC1_BASE 0x7001F000 +#define XUSB_HOST_BASE 0x70090000 +#define XUSB_PADCTL_BASE 0x7009F000 +#define XUSB_DEV_BASE 0x700D0000 #define MIPI_CAL_BASE 0x700E3000 #define CL_DVFS_BASE 0x70110000 #define I2S_BASE 0x702D1000 @@ -79,7 +82,7 @@ #define VIC(off) _REG(VIC_BASE, off) #define TSEC(off) _REG(TSEC_BASE, off) #define SOR1(off) _REG(SOR1_BASE, off) -#define ICTLR(cidx, off) _REG(ICTLR_BASE + (0x100 * cidx), off) +#define ICTLR(cidx, off) _REG(ICTLR_BASE + (0x100 * (cidx)), off) #define TMR(off) _REG(TMR_BASE, off) #define CLOCK(off) _REG(CLOCK_BASE, off) #define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) @@ -109,6 +112,12 @@ #define EMC(off) _REG(EMC_BASE, off) #define EMC_CH0(off) _REG(EMC0_BASE, off) #define EMC_CH1(off) _REG(EMC1_BASE, off) +#define XUSB_HOST(off) _REG(XUSB_HOST_BASE, off) +#define XUSB_PADCTL(off) _REG(XUSB_PADCTL_BASE, off) +#define XUSB_DEV(off) _REG(XUSB_DEV_BASE, off) +#define XUSB_DEV_XHCI(off) _REG(XUSB_DEV_BASE, off) +#define XUSB_DEV_PCI(off) _REG(XUSB_DEV_BASE + 0x8000, off) +#define XUSB_DEV_DEV(off) _REG(XUSB_DEV_BASE + 0x9000, off) #define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) #define CL_DVFS(off) _REG(CL_DVFS_BASE, off) #define I2S(off) _REG(I2S_BASE, off) @@ -149,14 +158,33 @@ /*! AHB Gizmo registers. */ #define AHB_ARBITRATION_PRIORITY_CTRL 0x8 -#define ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE (1 << 6) +#define PRIORITY_CTRL_WEIGHT(x) (((x) & 7) << 29) +#define PRIORITY_SELECT_USB BIT(6) // USB-OTG. +#define PRIORITY_SELECT_USB2 BIT(18) // USB-HSIC. +#define PRIORITY_SELECT_USB3 BIT(17) // XUSB. #define AHB_GIZMO_AHB_MEM 0x10 -#define AHB_MEM_ENB_FAST_REARBITRATE (1 << 2) +#define AHB_MEM_ENB_FAST_REARBITRATE BIT(2) +#define AHB_MEM_DONT_SPLIT_AHB_WR BIT(7) +#define AHB_MEM_IMMEDIATE BIT(18) +#define AHB_GIZMO_APB_DMA 0x14 #define AHB_GIZMO_USB 0x20 -#define AHB_GIZMO_USB_IMMEDIATE (1 << 18) +#define AHB_GIZMO_SDMMC4 0x48 +#define AHB_GIZMO_USB2 0x7C +#define AHB_GIZMO_USB3 0x80 +#define AHB_GIZMO_IMMEDIATE BIT(18) +#define AHB_ARBITRATION_XBAR_CTRL 0xE0 +#define AHB_AHB_MEM_PREFETCH_CFG3 0xE4 +#define AHB_AHB_MEM_PREFETCH_CFG4 0xE8 #define AHB_AHB_MEM_PREFETCH_CFG1 0xF0 -#define MEM_PREFETCH_ENABLE (1 << 31) -#define MEM_PREFETCH_AHB_MST_USB 6 +#define AHB_AHB_MEM_PREFETCH_CFG2 0xF4 +#define MST_ID(x) (((x) & 0x1F) << 26) +#define MEM_PREFETCH_AHBDMA_MST_ID MST_ID(5) +#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG. +#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC. +#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB. +#define MEM_PREFETCH_ADDR_BNDRY(x) (((x) & 0xF) << 21) +#define MEM_PREFETCH_ENABLE BIT(31) +#define AHB_AHB_SPARE_REG 0x110 /*! Misc registers. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 @@ -170,19 +198,16 @@ #define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 #define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC +#define APB_MISC_GP_DSI_PAD_CONTROL 0xAC0 #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 -/*! System registers. */ -#define AHB_ARBITRATION_XBAR_CTRL 0xE0 -#define AHB_AHB_SPARE_REG 0x110 - /*! Secure boot registers. */ #define SB_CSR 0x0 -#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) -#define SB_CSR_PIROM_DISABLE (1 << 4) +#define SB_CSR_NS_RST_VEC_WR_DIS BIT(1) +#define SB_CSR_PIROM_DISABLE BIT(4) #define SB_AA64_RESET_LOW 0x30 -#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) +#define SB_AA64_RST_AARCH64_MODE_EN BIT(0) #define SB_AA64_RESET_HIGH 0x34 /*! SOR registers. */ @@ -217,20 +242,20 @@ #define TIMERUS_USEC_CFG (0x10 + 0x4) #define TIMER_TMR8_TMR_PTV 0x78 #define TIMER_TMR9_TMR_PTV 0x80 -#define TIMER_EN (1 << 31) -#define TIMER_PER_EN (1 << 30) +#define TIMER_PER_EN BIT(30) +#define TIMER_EN BIT(31) #define TIMER_TMR8_TMR_PCR 0x7C #define TIMER_TMR9_TMR_PCR 0x8C -#define TIMER_INTR_CLR (1 << 30) +#define TIMER_INTR_CLR BIT(30) #define TIMER_WDT4_CONFIG (0x100 + 0x80) -#define TIMER_SRC(TMR) (TMR & 0xF) -#define TIMER_PER(PER) ((PER & 0xFF) << 4) -#define TIMER_SYSRESET_EN (1 << 14) -#define TIMER_PMCRESET_EN (1 << 15) +#define TIMER_SRC(TMR) ((TMR) & 0xF) +#define TIMER_PER(PER) (((PER) & 0xFF) << 4) +#define TIMER_SYSRESET_EN BIT(14) +#define TIMER_PMCRESET_EN BIT(15) #define TIMER_WDT4_COMMAND (0x108 + 0x80) -#define TIMER_START_CNT (1 << 0) -#define TIMER_CNT_DISABLE (1 << 1) +#define TIMER_START_CNT BIT(0) +#define TIMER_CNT_DISABLE BIT(1) #define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) #define TIMER_MAGIC_PTRN 0xC45A @@ -245,29 +270,29 @@ #define I2S4_CTRL 0x3A0 #define I2S5_CG 0x488 #define I2S5_CTRL 0x4A0 -#define I2S_CG_SLCG_ENABLE (1 << 0) -#define I2S_CTRL_MASTER_EN (1 << 10) +#define I2S_CG_SLCG_ENABLE BIT(0) +#define I2S_CTRL_MASTER_EN BIT(10) /*! PWM registers. */ #define PWM_CONTROLLER_PWM_CSR_0 0x00 #define PWM_CONTROLLER_PWM_CSR_1 0x10 -#define PWM_CSR_EN (1 << 31) +#define PWM_CSR_EN BIT(31) /*! Special registers. */ #define EMC_SCRATCH0 0x324 -#define EMC_HEKA_UPD (1 << 30) -#define EMC_SEPT_RUN (1 << 31) +#define EMC_HEKA_UPD BIT(30) +#define EMC_SEPT_RUN BIT(31) /*! Flow controller registers. */ #define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define HALT_COP_GIC_IRQ (1 << 9) -#define HALT_COP_LIC_IRQ (1 << 11) -#define HALT_COP_SEC (1 << 23) -#define HALT_COP_MSEC (1 << 24) -#define HALT_COP_USEC (1 << 25) -#define HALT_COP_JTAG (1 << 28) -#define HALT_COP_WAIT_EVENT (1 << 30) -#define HALT_COP_STOP_UNTIL_IRQ (1 << 31) +#define HALT_COP_GIC_IRQ BIT(9) +#define HALT_COP_LIC_IRQ BIT(11) +#define HALT_COP_SEC BIT(23) +#define HALT_COP_MSEC BIT(24) +#define HALT_COP_USEC BIT(25) +#define HALT_COP_JTAG BIT(28) +#define HALT_COP_WAIT_EVENT BIT(30) +#define HALT_COP_STOP_UNTIL_IRQ BIT(31) #define HALT_COP_MAX_CNT 0xFF #define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 #define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 @@ -280,9 +305,4 @@ #define FLOW_CTLR_RAM_REPAIR 0x40 #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 diff --git a/bdk/storage/mmc.h b/bdk/storage/mmc.h index dddb956..efa9e10 100644 --- a/bdk/storage/mmc.h +++ b/bdk/storage/mmc.h @@ -31,7 +31,7 @@ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #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_SELECT_CARD 7 /* ac [31:16] RCA 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_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr 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 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ @@ -136,8 +136,8 @@ c : clear by read #define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ #define R1_ERASE_RESET (1 << 13) /* sr, c */ -#define R1_STATUS(x) (x & 0xFFFFE000) -#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_STATUS(x) ((x) & 0xFFFFE000) +#define R1_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c index fc41458..43f837d 100644 --- a/bdk/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -48,15 +48,18 @@ static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) static int _sdmmc_storage_check_result(u32 res) { //Error mask: - //R1_OUT_OF_RANGE, R1_ADDRESS_ERROR, R1_BLOCK_LEN_ERROR, - //R1_ERASE_SEQ_ERROR, R1_ERASE_PARAM, R1_WP_VIOLATION, - //R1_LOCK_UNLOCK_FAILED, R1_COM_CRC_ERROR, R1_ILLEGAL_COMMAND, - //R1_CARD_ECC_FAILED, R1_CC_ERROR, R1_ERROR, R1_CID_CSD_OVERWRITE, - //R1_WP_ERASE_SKIP, R1_ERASE_RESET, R1_SWITCH_ERROR - if (!(res & 0xFDF9A080)) - return 1; - //TODO: R1_SWITCH_ERROR we can skip for certain card types. - return 0; + //TODO: R1_SWITCH_ERROR can be skipped for certain card types. + if (res & + (R1_OUT_OF_RANGE | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR | + R1_ERASE_SEQ_ERROR | R1_ERASE_PARAM | R1_WP_VIOLATION | + R1_LOCK_UNLOCK_FAILED | R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND | + R1_CARD_ECC_FAILED | R1_CC_ERROR | R1_ERROR | + R1_CID_CSD_OVERWRITE | R1_WP_ERASE_SKIP | R1_ERASE_RESET | + R1_SWITCH_ERROR)) + return 0; + + // No errors. + return 1; } static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state, u32 mask) @@ -169,14 +172,23 @@ int sdmmc_storage_end(sdmmc_storage_t *storage) sdmmc_end(storage->sdmmc); + storage->initialized = 0; + return 1; } static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) { u8 *bbuf = (u8 *)buf; - bool first_reinit = false; - while (num_sectors) + u32 sct_off = sector; + u32 sct_total = num_sectors; + bool first_reinit = true; + + // Exit if not initialized. + if (!storage->initialized) + return 0; + + while (sct_total) { u32 blkcnt = 0; // Retry 5 times if failed. @@ -184,7 +196,7 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu 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, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write)) goto out; else retries--; @@ -201,7 +213,7 @@ reinit_try: sd_error_count_increment(SD_ERROR_RW_FAIL); - if (!first_reinit) + if (first_reinit) res = sd_initialize(true); else { @@ -210,19 +222,28 @@ reinit_try: sd_error_count_increment(SD_ERROR_INIT_FAIL); } + // Reset values for a retry. + blkcnt = 0; retries = 3; - first_reinit = true; + first_reinit = false; + // If succesful reinit, restart xfer. if (res) + { + bbuf = (u8 *)buf; + sct_off = sector; + sct_total = num_sectors; + goto reinit_try; + } } + // Failed. return 0; out: -DPRINTF("readwrite: %08X\n", blkcnt); - sector += blkcnt; - num_sectors -= blkcnt; + sct_off += blkcnt; + sct_total -= blkcnt; bbuf += 512 * blkcnt; } @@ -275,9 +296,11 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u case SDMMC_POWER_1_8: arg = SD_OCR_CCS | SD_OCR_VDD_18; break; + case SDMMC_POWER_3_3: arg = SD_OCR_CCS | SD_OCR_VDD_27_34; break; + default: return 0; } @@ -334,6 +357,7 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4); storage->cid.serial = unstuff_bits(raw_cid, 16, 24); break; + case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ @@ -343,6 +367,7 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) storage->cid.prv = unstuff_bits(raw_cid, 48, 8); storage->cid.serial = unstuff_bits(raw_cid, 16, 32); break; + default: break; } @@ -387,6 +412,10 @@ static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; + storage->ext_csd.pre_eol_info = buf[EXT_CSD_PRE_EOL_INFO]; + storage->ext_csd.dev_life_est_a = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; + storage->ext_csd.dev_life_est_b = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; + storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; } @@ -429,6 +458,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) case SDMMC_BUS_WIDTH_4: arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); break; + case SDMMC_BUS_WIDTH_8: arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8); break; @@ -487,7 +517,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) if (!_mmc_storage_enable_HS200(storage)) return 0; - sdmmc_set_tap_value(storage->sdmmc); + sdmmc_save_tap_value(storage->sdmmc); if (!_mmc_storage_enable_HS(storage, 0)) return 0; @@ -543,7 +573,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_wid storage->sdmmc = sdmmc; storage->rca = 2; //TODO: this could be a config item. - if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE)) + if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[MMC] after init\n"); @@ -614,7 +644,9 @@ DPRINTF("[MMC] BKOPS enabled\n"); return 0; DPRINTF("[MMC] succesfully switched to HS mode\n"); - sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE); + sdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE); + + storage->initialized = 1; return 1; } @@ -628,6 +660,7 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) return 0; storage->partition = partition; + return 1; } @@ -666,7 +699,7 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage) return (resp & 0xFF) == 0xAA ? 0 : 2; } -static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage) +static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int bus_low_voltage_support) { sdmmc_cmd_t cmdbuf; // Support for Current > 150mA @@ -674,7 +707,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int // Support for handling block-addressed SDHC cards arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; // Support for 1.8V - arg |= (supports_low_voltage & ~is_version_1 & 1) ? SD_OCR_S18R : 0; + arg |= (bus_low_voltage_support & ~is_version_1 & 1) ? SD_OCR_S18R : 0; // This is needed for most cards. Do not set bit7 even if 1.8V is supported. arg |= SD_OCR_VDD_32_33; sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); @@ -684,22 +717,24 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } -static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int supports_low_voltage) +static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int bus_low_voltage_support) { u32 timeout = get_tmr_ms() + 1500; while (1) { u32 cond = 0; - if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage)) + if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, bus_low_voltage_support)) break; if (cond & MMC_CARD_BUSY) { +DPRINTF("[SD] cond: %08X, lv: %d\n", cond, bus_low_voltage_support); + if (cond & SD_OCR_CCS) 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 && bus_low_voltage_support) { //The low voltage regulator configuration is valid for SDMMC1 only. if (storage->sdmmc->id == SDMMC_1 && @@ -712,6 +747,10 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i DPRINTF("-> switched to low voltage\n"); } } + else + { +DPRINTF("[SD] no low voltage support\n"); + } return 1; } @@ -867,12 +906,15 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, 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"); break; + case SD_SET_CURRENT_LIMIT_400: DPRINTF("[SD] power limit raised to 400mA\n"); break; + default: case SD_SET_CURRENT_LIMIT_200: DPRINTF("[SD] power limit defaulted to 200mA\n"); @@ -885,7 +927,7 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) return 0; -DPRINTF("[SD] supports switch to (U)HS mode\n"); +DPRINTF("[SD] supports (U)HS mode: %d\n", buf[16] & 0xF); u32 type_out = buf[16] & 0xF; if (type_out != hs_type) @@ -921,6 +963,7 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) u8 access_mode = buf[13]; u16 current_limit = buf[7] | buf[6] << 8; +DPRINTF("[SD] access: %02X, current: %02X\n", access_mode, current_limit); // Try to raise the current limit to let the card perform better. _sd_storage_set_current_limit(storage, current_limit, buf); @@ -959,7 +1002,7 @@ DPRINTF("[SD] bus speed set to SDR50\n"); if (access_mode & SD_MODE_UHS_SDR25) { type = SDHCI_TIMING_UHS_SDR25; - hs_type = UHS_SDR50_BUS_SPEED; + hs_type = UHS_SDR25_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR25\n"); storage->csd.busspeed = 25; break; @@ -972,6 +1015,7 @@ DPRINTF("[SD] bus speed set to SDR25\n"); DPRINTF("[SD] bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; + default: return 0; break; @@ -982,10 +1026,10 @@ DPRINTF("[SD] bus speed set to SDR12\n"); DPRINTF("[SD] card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; -DPRINTF("[SD] setup clock\n"); +DPRINTF("[SD] after setup clock\n"); if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; -DPRINTF("[SD] config tuning\n"); +DPRINTF("[SD] after tuning\n"); return _sdmmc_storage_check_status(storage); } @@ -1030,23 +1074,30 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) raw_ssr2[0] = *(u32 *)&storage->raw_ssr[16]; storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1; + storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448 - 384, 32); + switch(unstuff_bits(raw_ssr1, 440 - 384, 8)) { case 0: storage->ssr.speed_class = 0; break; + case 1: storage->ssr.speed_class = 2; break; + case 2: storage->ssr.speed_class = 4; break; + case 3: storage->ssr.speed_class = 6; break; + case 4: storage->ssr.speed_class = 10; break; + default: storage->ssr.speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); break; @@ -1126,6 +1177,7 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) case 0: storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); break; + case 1: storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22)); storage->csd.capacity = storage->csd.c_size << 10; @@ -1134,7 +1186,7 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) } } -static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type) +static bool _sdmmc_storage_get_low_voltage_support(u32 bus_width, u32 type) { switch (type) { @@ -1153,9 +1205,10 @@ static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type) void sdmmc_storage_init_wait_sd() { + // T210/T210B01 WAR: Wait exactly 239ms for IO and Controller power to discharge. u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; - if (sd_poweroff_time < 100) - msleep(100 - sd_poweroff_time); + if (sd_poweroff_time < 239) + msleep(239 - sd_poweroff_time); } int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) @@ -1163,13 +1216,15 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_widt int is_version_1 = 0; u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; +DPRINTF("[SD] init: bus: %d, type: %d\n", bus_width, type); + // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. sdmmc_storage_init_wait_sd(); memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; - if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE)) + if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[SD] after init\n"); @@ -1184,9 +1239,9 @@ DPRINTF("[SD] went to idle state\n"); return 0; DPRINTF("[SD] after send if cond\n"); - bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type); + bool bus_low_voltage_support = _sdmmc_storage_get_low_voltage_support(bus_width, type); - if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage)) + if (!_sd_storage_get_op_cond(storage, is_version_1, bus_low_voltage_support)) return 0; DPRINTF("[SD] got op cond\n"); @@ -1264,7 +1319,7 @@ DPRINTF("[SD] SD does not support wide bus width\n"); return 0; DPRINTF("[SD] enabled UHS\n"); - sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE); + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); } else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0) { @@ -1277,6 +1332,7 @@ DPRINTF("[SD] enabled HS\n"); case SDMMC_BUS_WIDTH_4: storage->csd.busspeed = 25; break; + case SDMMC_BUS_WIDTH_1: storage->csd.busspeed = 6; break; @@ -1289,6 +1345,8 @@ DPRINTF("[SD] enabled HS\n"); DPRINTF("[SD] got sd status\n"); } + storage->initialized = 1; + return 1; } @@ -1328,17 +1386,19 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; - if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE)) + if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS102, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); - if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200)) + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS102, MMC_SEND_TUNING_BLOCK_HS200)) return 0; DPRINTF("[gc] after tuning\n"); - sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE); + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); + + storage->initialized = 1; return 1; } diff --git a/bdk/storage/sdmmc.h b/bdk/storage/sdmmc.h index 6bfad77..68d70f0 100644 --- a/bdk/storage/sdmmc.h +++ b/bdk/storage/sdmmc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-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, @@ -65,16 +65,19 @@ typedef struct _mmc_csd typedef struct _mmc_ext_csd { - u8 rev; u32 sectors; int bkops; /* background support bit */ int bkops_en; /* manual bkops enable bit */ + u8 rev; u8 ext_struct; /* 194 */ u8 card_type; /* 196 */ u8 bkops_status; /* 246 */ - u16 dev_version; + u8 pre_eol_info; + u8 dev_life_est_a; + u8 dev_life_est_b; u8 boot_mult; u8 rpmb_mult; + u16 dev_version; } mmc_ext_csd_t; typedef struct _sd_scr @@ -92,6 +95,7 @@ typedef struct _sd_ssr u8 uhs_grade; u8 video_class; u8 app_class; + u32 protected_size; } sd_ssr_t; /*! SDMMC storage context. */ @@ -112,6 +116,7 @@ typedef struct _sdmmc_storage_t mmc_ext_csd_t ext_csd; sd_scr_t scr; sd_ssr_t ssr; + int initialized; } sdmmc_storage_t; int sdmmc_storage_end(sdmmc_storage_t *storage); diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c index 557fe8d..3eaded0 100644 --- a/bdk/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -1,6 +1,6 @@ /* * 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 * under the terms and conditions of the GNU General Public License, @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -65,12 +66,15 @@ static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power) case SDMMC_POWER_OFF: sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON; break; + case SDMMC_POWER_1_8: sdmmc->regs->pwrcon = SDHCI_POWER_180; break; + case SDMMC_POWER_3_3: sdmmc->regs->pwrcon = SDHCI_POWER_330; break; + default: return 0; } @@ -103,7 +107,7 @@ void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; } -void sdmmc_set_tap_value(sdmmc_t *sdmmc) +void sdmmc_save_tap_value(sdmmc_t *sdmmc) { sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; sdmmc->venclkctl_set = 1; @@ -112,7 +116,7 @@ void sdmmc_set_tap_value(sdmmc_t *sdmmc) static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) { const u32 dqs_trim_val = 0x28; - const u32 tap_values[] = { 4, 0, 3, 0 }; + const u32 tap_values_t210[] = { 4, 0, 3, 0 }; u32 tap_val = 0; @@ -129,36 +133,49 @@ static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) tap_val = sdmmc->venclkctl_tap; } else - { - tap_val = tap_values[sdmmc->id]; - } + tap_val = sdmmc->t210b01 ? 11 : tap_values_t210[sdmmc->id]; + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); return 1; } -static int _sdmmc_get_clkcon(sdmmc_t *sdmmc) +static int _sdmmc_commit_changes(sdmmc_t *sdmmc) { return sdmmc->regs->clkcon; } static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) { - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); switch (sdmmc->id) { case SDMMC_1: // 33 Ohm 2X Driver. if (power == SDMMC_POWER_OFF) break; u32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF; - if (power == SDMMC_POWER_1_8) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. + if (sdmmc->t210b01) + sdmmc1_pad_cfg |= (0x808 << 12); // Up: 8, Dn: 8. For 33 ohm. + else if (power == SDMMC_POWER_1_8) + sdmmc1_pad_cfg |= (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. else if (power == SDMMC_POWER_3_3) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. + sdmmc1_pad_cfg |= (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg; + (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. break; + case SDMMC_2: - case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16. - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; + if (sdmmc->t210b01) + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xF8080FFF) | 0xA0A000; + else + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; // PU:16, PD:16. + (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); + break; + + case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16, B01: PU:10, PD:10. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = + (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | (sdmmc->t210b01 ? 0xA28 : 0x1040); + (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. break; } } @@ -176,13 +193,13 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD)) { sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep(1); } // Enable auto calibration and start auto configuration. sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep(2); u32 timeout = get_tmr_ms() + 10; @@ -194,24 +211,18 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) break; } } -/* - // Check if PU results are inside limits. - // SDMMC1: CZ pads - 7-bit PU. SDMMC2/4: LV_CZ pads - 5-bit PU. - u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x7F; - switch (sdmmc->id) - { - case SDMMC_1: - if (!autocal_pu_status || autocal_pu_status == 0x7F) - timeout = 0; - break; - case SDMMC_2: - case SDMMC_4: - autocal_pu_status &= 0x1F; - if (!autocal_pu_status || autocal_pu_status == 0x1F) - timeout = 0; - break; - } -*/ + +#ifdef ERROR_EXTRA_PRINTING + // Check if Comp pad is open or short to ground. + // SDMMC1: CZ pads - T210/T210B01: 7-bit/5-bit. SDMMC2/4: LV_CZ pads - 5-bit. + u8 code_mask = (sdmmc->t210b01 || sdmmc->id != SDMMC_1) ? 0x1F : 0x7F; + u8 autocal_pu_status = sdmmc->regs->autocalsts & code_mask; + if (!autocal_pu_status) + EPRINTF("SDMMC: Comp Pad short to gnd!"); + else if (autocal_pu_status == code_mask) + EPRINTF("SDMMC: Comp Pad open!"); +#endif + // In case auto calibration fails, we load suggested standard values. if (!timeout) { @@ -241,12 +252,13 @@ static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) } #ifdef SDMMC_EMMC_OC + // Add -4 TX_DLY_CODE_OFFSET if HS533. if (sdmmc->id == SDMMC_4 && overclock) - sdmmc->regs->vendllcalcfg = sdmmc->regs->vendllcalcfg &= 0xFFFFC07F | (0x7C << 7); // Add -4 TX_DLY_CODE_OFFSET if HS533. + sdmmc->regs->vendllcalcfg = sdmmc->regs->vendllcalcfg &= 0xFFFFC07F | (0x7C << 7); #endif sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 5; while (sdmmc->regs->vendllcalcfg & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE) @@ -277,12 +289,21 @@ out:; static void _sdmmc_reset(sdmmc_t *sdmmc) { sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000; while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout) ; } +static void _sdmmc_reset_all(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= SDHCI_RESET_ALL; + _sdmmc_commit_changes(sdmmc); + u32 timeout = get_tmr_ms() + 2000;//100ms + while ((sdmmc->regs->swrst & SDHCI_RESET_ALL) && get_tmr_ms() < timeout) + ; +} + int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) { // Disable the SD clock if it was enabled, and reenable it later. @@ -306,36 +327,41 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD; sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; + case SDHCI_TIMING_MMC_HS52: case SDHCI_TIMING_SD_HS25: sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD; sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; + case SDHCI_TIMING_MMC_HS200: case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104. case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR82: case SDHCI_TIMING_UHS_DDR50: - case SDHCI_TIMING_MMC_DDR52: + case SDHCI_TIMING_MMC_HS102: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; + case SDHCI_TIMING_MMC_HS400: // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; + case SDHCI_TIMING_UHS_SDR25: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; + case SDHCI_TIMING_UHS_SDR12: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; } - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 clock; u16 divisor; @@ -373,10 +399,10 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc) { // Recalibrate conditionally. - if ((sdmmc->id == SDMMC_1) && !sdmmc->auto_cal_enabled) + if (sdmmc->manual_cal && !sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); - if (!sdmmc->auto_cal_enabled) + if (!sdmmc->powersave_enabled) { if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; @@ -390,18 +416,17 @@ static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } -void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable) +void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable) { // Recalibrate periodically for SDMMC1. - if ((sdmmc->id == SDMMC_1) && !auto_cal_enable && sdmmc->card_clock_enabled) + if (sdmmc->manual_cal && !powersave_enable && sdmmc->card_clock_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); - sdmmc->auto_cal_enabled = auto_cal_enable; - if (auto_cal_enable) + sdmmc->powersave_enabled = powersave_enable; + if (powersave_enable) { - if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) - return; - sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return; } @@ -422,6 +447,7 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) return 0; rsp[0] = sdmmc->regs->rspreg0; break; + case SDMMC_RSP_TYPE_2: if (size < 0x10) return 0; @@ -450,9 +476,9 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) rsp[i - 1] |= (tempreg >> 24) & 0xFF; } break; + default: return 0; - break; } return 1; @@ -473,6 +499,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) return 0; rsp[0] = sdmmc->rsp[0]; break; + case SDMMC_RSP_TYPE_2: if (size < 0x10) return 0; @@ -481,9 +508,9 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) rsp[2] = sdmmc->rsp[2]; rsp[3] = sdmmc->rsp[3]; break; + default: return 0; - break; } return 1; @@ -491,7 +518,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) { - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000; while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT) @@ -517,7 +544,7 @@ static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc) { - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000; while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK)) @@ -536,16 +563,19 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) { case SDMMC_BUS_WIDTH_1: return 0; - break; + case SDMMC_BUS_WIDTH_4: sdmmc->regs->blksize = 64; break; + case SDMMC_BUS_WIDTH_8: sdmmc->regs->blksize = 128; break; } + sdmmc->regs->blkcnt = 1; sdmmc->regs->trnmod = SDHCI_TRNS_READ; + return 1; } @@ -557,6 +587,7 @@ static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_presen { case SDMMC_RSP_TYPE_0: break; + case SDMMC_RSP_TYPE_1: case SDMMC_RSP_TYPE_4: case SDMMC_RSP_TYPE_5: @@ -565,15 +596,17 @@ static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_presen else cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; break; + case SDMMC_RSP_TYPE_2: cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC; break; + case SDMMC_RSP_TYPE_3: cmdflags = SDHCI_CMD_RESP_LEN48; break; + default: return 0; - break; } if (is_data_present) @@ -596,7 +629,7 @@ static void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd) static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) { - if (sdmmc->auto_cal_enabled) + if (sdmmc->powersave_enabled) return 0; if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true)) return 0; @@ -608,13 +641,13 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; _sdmmc_send_tuning_cmd(sdmmc, cmd); - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep(1); _sdmmc_reset(sdmmc); sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_us() + 5000; while (get_tmr_us() < timeout) @@ -623,7 +656,7 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) { sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL; sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 1; } @@ -632,7 +665,7 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) _sdmmc_reset(sdmmc); sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 0; @@ -651,15 +684,18 @@ int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd) max = 128; flag = (2 << 13); // 128 iterations. break; + case SDHCI_TIMING_UHS_SDR50: case SDHCI_TIMING_UHS_DDR50: - case SDHCI_TIMING_MMC_DDR52: + case SDHCI_TIMING_MMC_HS102: max = 256; flag = (4 << 13); // 256 iterations. break; + case SDHCI_TIMING_UHS_SDR12: case SDHCI_TIMING_UHS_SDR25: return 1; + default: return 0; } @@ -688,7 +724,7 @@ static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) { //Enable internal clock and wait till it is stable. sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000; while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE)) { @@ -724,17 +760,28 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) off_pd = 5; off_pu = 5; break; + case SDMMC_1: - case SDMMC_3: if (power == SDMMC_POWER_1_8) { - off_pd = 123; - off_pu = 123; + if (!sdmmc->t210b01) + { + off_pd = 123; + off_pu = 123; + } + else + { + off_pd = 6; + off_pu = 6; + } } else if (power == SDMMC_POWER_3_3) { - off_pd = 125; - off_pu = 0; + if (!sdmmc->t210b01) + { + off_pd = 125; + off_pu = 0; + } } else return 0; @@ -764,7 +811,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) u16 norintsts = sdmmc->regs->norintsts; u16 errintsts = sdmmc->regs->errintsts; -DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); +DPRINTF("norintsts %08X, errintsts %08X\n", norintsts, errintsts); if (pout) *pout = norintsts; @@ -772,6 +819,9 @@ DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); // Check for error interrupt. if (norintsts & SDHCI_INT_ERROR) { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC: norintsts %08X, errintsts %08X\n", norintsts, errintsts); +#endif sdmmc->regs->errintsts = errintsts; return SDMMC_MASKINT_ERROR; } @@ -786,7 +836,7 @@ DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); static int _sdmmc_wait_response(sdmmc_t *sdmmc) { - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000; while (true) @@ -837,7 +887,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) return 0; // Recalibrate periodically for SDMMC1. - if ((sdmmc->id == SDMMC_1) && sdmmc->auto_cal_enabled) + if (sdmmc->manual_cal && sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); bool should_disable_sd_clock = false; @@ -845,7 +895,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) { should_disable_sd_clock = true; sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } @@ -963,8 +1013,6 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ is_data_present = true; } - else - is_data_present = false; _sdmmc_enable_interrupts(sdmmc); @@ -983,7 +1031,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ EPRINTF("SDMMC: Transfer timeout!"); #endif } - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, +DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (result) { @@ -994,7 +1042,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ if (!result) { #ifdef ERROR_EXTRA_PRINTING - EPRINTFARGS("SDMMC: Unknown response %08X!", sdmmc->rsp[0]); + EPRINTF("SDMMC: Unknown response type!"); #endif } } @@ -1004,7 +1052,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ if (!result) { #ifdef ERROR_EXTRA_PRINTING - EPRINTF("SDMMC: DMA Update failed!"); + EPRINTFARGS("SDMMC: DMA Update failed (%08X)!", result); #endif } } @@ -1047,7 +1095,56 @@ bool sdmmc_get_sd_inserted() return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)); } -static int _sdmmc_config_sdmmc1() +static void _sdmmc_config_sdmmc1_schmitt() +{ + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; +} + +static void _sdmmc_config_sdmmc2_schmitt() +{ + PINMUX_AUX(PINMUX_AUX_SDMMC2_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT7) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT6) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT5) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT4) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT0) |= PINMUX_SCHMT; +} + +static void _sdmmc_config_sdmmc1_pads(bool discharge) +{ + u32 sdmmc1_pin_mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5; + + // Set values for Reset state. + u32 function = GPIO_MODE_SPIO; + u32 level = GPIO_LOW; + u32 output = GPIO_OUTPUT_DISABLE; + + // Set values for dicharging. + if (discharge) + { + function = GPIO_MODE_GPIO; + level = GPIO_HIGH; + output = GPIO_OUTPUT_ENABLE; + } + + // Set all pads function. + gpio_config(GPIO_PORT_M, sdmmc1_pin_mask, function); + // Set all pads output level. + gpio_write(GPIO_PORT_M, sdmmc1_pin_mask, level); + // Set all pads output. + gpio_output_enable(GPIO_PORT_M, sdmmc1_pin_mask, output); +} + +static int _sdmmc_config_sdmmc1(bool t210b01) { // Configure SD card detect. PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up. @@ -1062,74 +1159,101 @@ static int _sdmmc_config_sdmmc1() /* * Pinmux config: - * DRV_TYPE = DRIVE_2X + * DRV_TYPE = DRIVE_2X (for 33 Ohm driver) * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) * E_INPUT = ENABLE * TRISTATE = PASSTHROUGH * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK */ - // Configure SDMMC1 pinmux. - APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + // Enable deep loopback for SDMMC1 CLK pad. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; + + // Configure SDMMC1 CLK pinmux, based on state and SoC type. + if (PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) != (PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN)) // Check if CLK pad is already configured. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | (t210b01 ? PINMUX_PULL_NONE : PINMUX_PULL_DOWN); + + // Configure reset state of SDMMC1 pins pinmux. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + + // Force schmitt trigger for T210B01. + if (t210b01) + _sdmmc_config_sdmmc1_schmitt(); // Make sure the SDMMC1 controller is powered. - PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN; - usleep(1000); PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN); + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. // Inform IO pads that voltage is gonna be 3.3V. PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. // Set enable SD card power. PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Pull down. gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); - usleep(1000); + usleep(10000); - // Enable SD card power. + // Enable SD card IO power. max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); max77620_regulator_enable(REGULATOR_LDO2, 1); usleep(1000); // Set pad slew codes to get good quality clock. - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; - usleep(1000); + if (!t210b01) + { + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; + (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. + usleep(1000); + } return 1; } -static void _sdmmc_config_emmc(u32 id) +static void _sdmmc_config_emmc(u32 id, bool t210b01) { switch (id) { case SDMMC_2: - // Unset park for pads. - APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; + if (!t210b01) + { + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; + (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); // Commit write. + } + else // Enable schmitt trigger for T210B01. + _sdmmc_config_sdmmc2_schmitt(); break; + case SDMMC_4: // Unset park for pads. APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF; // Set default pad cfg. - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; - - // Enabled schmitt trigger. - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; // Enable Schmitt trigger. + if (t210b01) + APB_MISC(APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL) &= 0xFFBFFFF9; // Unset CMD/CLK/DQS powedown. + // Enable schmitt trigger. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; + (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. break; } } -int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable) +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable) { - const u32 trim_values[] = { 2, 8, 3, 8 }; + u32 clock; + u16 divisor; + u8 vref_sel = 7; - if (id > SDMMC_4) + const u32 trim_values_t210[] = { 2, 8, 3, 8 }; + const u32 trim_values_t210b01[] = { 14, 13, 15, 13 }; + const u32 *trim_values = sdmmc->t210b01 ? trim_values_t210b01 : trim_values_t210; + + if (id > SDMMC_4 || id == SDMMC_3) return 0; memset(sdmmc, 0, sizeof(sdmmc_t)); @@ -1137,45 +1261,57 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a sdmmc->regs = (t210_sdmmc_t *)_sdmmc_bases[id]; sdmmc->id = id; sdmmc->clock_stopped = 1; + sdmmc->t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; // Do specific SDMMC HW configuration. switch (id) { case SDMMC_1: - if (!_sdmmc_config_sdmmc1()) + if (!_sdmmc_config_sdmmc1(sdmmc->t210b01)) return 0; + if (sdmmc->t210b01) + vref_sel = 0; + else + sdmmc->manual_cal = 1; break; + case SDMMC_2: case SDMMC_4: - _sdmmc_config_emmc(id); + _sdmmc_config_emmc(id, sdmmc->t210b01); break; } + // Disable clock if enabled. if (clock_sdmmc_is_not_reset_and_enabled(id)) { _sdmmc_sd_clock_disable(sdmmc); - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); } - u32 clock; - u16 divisor; + // Configure and enable selected clock. clock_sdmmc_get_card_clock_div(&clock, &divisor, type); clock_sdmmc_enable(id, clock); + // Make sure all sdmmc registers are reset. + _sdmmc_reset_all(sdmmc); + sdmmc->clock_stopped = 0; - //TODO: make this skip-able. + // Set default pad IO trimming configuration. sdmmc->regs->iospare |= 0x80000; // Enable muxing. sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; // Set Band Gap VREG to supply DLL. sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | (trim_values[sdmmc->id] << 24); sdmmc->regs->sdmemcmppadctl = - (sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7; + (sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | vref_sel; + // Configure auto calibration values. if (!_sdmmc_autocal_config_offset(sdmmc, power)) return 0; + // Calibrate pads. _sdmmc_autocal_execute(sdmmc, power); + // Enable internal clock and power. if (_sdmmc_enable_internal_clock(sdmmc)) { sdmmc_set_bus_width(sdmmc, bus_width); @@ -1183,18 +1319,63 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a if (sdmmc_setup_clock(sdmmc, type)) { - sdmmc_card_clock_ctrl(sdmmc, auto_cal_enable); + sdmmc_card_clock_powersave(sdmmc, powersave_enable); _sdmmc_card_clock_enable(sdmmc); - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); return 1; } - - return 0; } + return 0; } +void sdmmc1_disable_power() +{ + // Ensure regulator is into default voltage. + if (PMC(APBDEV_PMC_PWR_DET_VAL) & PMC_PWR_DET_SDMMC1_IO_EN) + { + // Switch to 1.8V and wait for regulator to stabilize. + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); + usleep(150); + + // Inform IO pads that we switched to 1.8V. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN); + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + } + + // T210B01 WAR: Clear pull down from CLK pad. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK; + + // T210B01 WAR: Set pads to discharge state. + _sdmmc_config_sdmmc1_pads(true); + + // Disable SD card IO power regulator. + max77620_regulator_enable(REGULATOR_LDO2, 0); + usleep(4000); + + // Disable SD card IO power pin. + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); + + // T210/T210B01 WAR: Set start timer for IO and Controller power discharge. + sd_power_cycle_time_start = get_tmr_ms(); + usleep(1000); // To power cycle, min 1ms without power is needed. + + // Disable SDMMC1 controller power. + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN; + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. + + // Inform IO pads that next voltage might be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + + // T210B01 WAR: Restore pads to reset state. + _sdmmc_config_sdmmc1_pads(false); + + // T210B01 WAR: Restore pull down to CLK pad. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_PULL_DOWN; +} + void sdmmc_end(sdmmc_t *sdmmc) { if (!sdmmc->clock_stopped) @@ -1205,18 +1386,9 @@ void sdmmc_end(sdmmc_t *sdmmc) // Disable SD card power. if (sdmmc->id == SDMMC_1) - { - gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); - max77620_regulator_enable(REGULATOR_LDO2, 0); + sdmmc1_disable_power(); - // Inform IO pads that next voltage might be 3.3V. - PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; - - sd_power_cycle_time_start = get_tmr_ms(); // Some SanDisk U1 cards need 100ms for a power cycle. - usleep(1000); // To power cycle, min 1ms without power is needed. - } - - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); clock_sdmmc_disable(sdmmc->id); sdmmc->clock_stopped = 1; } @@ -1236,7 +1408,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b return 0; // Recalibrate periodically for SDMMC1. - if (sdmmc->id == SDMMC_1 && sdmmc->auto_cal_enabled) + if (sdmmc->manual_cal && sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); int should_disable_sd_clock = 0; @@ -1244,7 +1416,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b { should_disable_sd_clock = 1; sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } @@ -1265,36 +1437,32 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12)) return 0; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); - usleep(300); + usleep(150); // Inform IO pads that we switched to 1.8V. PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN); + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. // Enable schmitt trigger for better duty cycle and low jitter clock. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; + _sdmmc_config_sdmmc1_schmitt(); _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); _sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8); - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); msleep(5); // Wait minimum 5ms before turning on the card clock. // Turn on SDCLK. if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; - _sdmmc_get_clkcon(sdmmc); + _sdmmc_commit_changes(sdmmc); usleep(1000); - if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) + if ((sdmmc->regs->prnsts & SDHCI_DATA_LVL_MASK) == SDHCI_DATA_LVL_MASK) return 1; } diff --git a/bdk/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h index 2937d93..fb2b1b3 100644 --- a/bdk/storage/sdmmc_driver.h +++ b/bdk/storage/sdmmc_driver.h @@ -195,13 +195,13 @@ #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_TIMING_MMC_HS102 14 #define SDHCI_CAN_64BIT 0x10000000 /*! SDMMC Low power features. */ -#define SDMMC_AUTO_CAL_DISABLE 0 -#define SDMMC_AUTO_CAL_ENABLE 1 +#define SDMMC_POWER_SAVE_DISABLE 0 +#define SDMMC_POWER_SAVE_ENABLE 1 /*! Helper for SWITCH command argument. */ #define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) @@ -213,7 +213,8 @@ typedef struct _sdmmc_t u32 id; u32 divisor; u32 clock_stopped; - int auto_cal_enabled; + int powersave_enabled; + int manual_cal; int card_clock_enabled; int venclkctl_set; u32 venclkctl_tap; @@ -221,6 +222,7 @@ typedef struct _sdmmc_t u32 dma_addr_next; u32 rsp[4]; u32 rsp3; + int t210b01; } sdmmc_t; /*! SDMMC command. */ @@ -246,14 +248,14 @@ typedef struct _sdmmc_req_t int sdmmc_get_io_power(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_tap_value(sdmmc_t *sdmmc); +void sdmmc_save_tap_value(sdmmc_t *sdmmc); int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); -void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable); +void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable); int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd); int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); bool sdmmc_get_sd_inserted(); -int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable); +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable); void sdmmc_end(sdmmc_t *sdmmc); 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); diff --git a/bdk/storage/sdmmc_t210.h b/bdk/storage/sdmmc_t210.h index c5ecf11..2c1b3a5 100644 --- a/bdk/storage/sdmmc_t210.h +++ b/bdk/storage/sdmmc_t210.h @@ -103,6 +103,7 @@ typedef struct _t210_sdmmc_t vu32 iospare; vu32 mcciffifoctl; vu32 timeoutwcoal; + vu32 unk1; } t210_sdmmc_t; #endif diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c index 686f9e8..f39b082 100644 --- a/bdk/thermal/fan.c +++ b/bdk/thermal/fan.c @@ -38,7 +38,7 @@ void set_fan_duty(u32 duty) gpio_config(GPIO_PORT_S, GPIO_PIN_7, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_S, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); - PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Max PWM to disable fan. + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Max PWM to disable fan. PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. gpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode. @@ -55,7 +55,7 @@ void set_fan_duty(u32 duty) // If disabled send a 0 duty. if (inv_duty == 236) { - PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Bit 24 is absolute 0%. + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Bit 24 is absolute 0%. regulator_disable_5v(REGULATOR_5V_FAN); // Disable fan. diff --git a/bdk/usb/usb_descriptor_types.h b/bdk/usb/usb_descriptor_types.h new file mode 100644 index 0000000..9f86e9d --- /dev/null +++ b/bdk/usb/usb_descriptor_types.h @@ -0,0 +1,238 @@ +/* + * USB driver for Tegra X1 + * + * 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 . + */ + +#ifndef _USB_DESCRIPTORS_TYPES_H_ +#define _USB_DESCRIPTORS_TYPES_H_ + +#include + +typedef enum { + USB_DESCRIPTOR_DEVICE = 1, + USB_DESCRIPTOR_CONFIGURATION = 2, + USB_DESCRIPTOR_STRING = 3, + USB_DESCRIPTOR_INTERFACE = 4, + USB_DESCRIPTOR_ENDPOINT = 5, + USB_DESCRIPTOR_DEVICE_QUALIFIER = 6, + USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + USB_DESCRIPTOR_INTERFACE_POWER = 8, + USB_DESCRIPTOR_INTERFACE_OTG = 9, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT = 15, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP = 16, + USB_DESCRIPTOR_HID = 33, + USB_DESCRIPTOR_HID_REPORT = 34 +} usb_desc_type_t; + +typedef enum { + USB_DESCRIPTOR_MS_COMPAT_ID = 4, + USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5 +} usb_vendor_desc_type_t; + +typedef enum { + USB_ATTR_REMOTE_WAKE_UP = 0x20, + USB_ATTR_SELF_POWERED = 0x40, + USB_ATTR_BUS_POWERED_RSVD = 0x80 +} usb_cfg_attr_type_t; + +typedef enum +{ + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISO = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INTR = 3 +} usb_cfg_ep_type_t; + +/* Device descriptor structure */ +typedef struct _usb_dev_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u16 idVendor; // Vendor ID assigned by USB forum. + u16 idProduct; // Product ID assigned by Organization. + u16 bcdDevice; // Device Release number in BCD. + u8 iManufacturer; // Index of String descriptor describing Manufacturer. + u8 iProduct; // Index of String descriptor describing Product. + u8 iSerialNumber; // Index of String descriptor describing Serial number. + u8 bNumConfigs; // Number of possible configuration. +} __attribute__((packed)) usb_dev_descr_t; + +/* Device Qualifier descriptor structure */ +typedef struct _usb_dev_qual_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u8 bNumOtherConfigs; // Number of possible other-speed configurations. + u8 bReserved; // Reserved for future use, must be zero +} __attribute__((packed)) usb_dev_qual_descr_t; + +/* Configuration descriptor structure */ +typedef struct _usb_cfg_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + u16 wTotalLength; // Total length of all descriptors for this configuration. + u8 bNumInterfaces; // Number of interfaces in this configuration. + u8 bConfigurationValue; // Value of this configuration (1 based). + u8 iConfiguration; // Index of String Descriptor describing the configuration. + u8 bmAttributes; // Configuration characteristics. + u8 bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) usb_cfg_descr_t; + +/* Interface descriptor structure */ +typedef struct _usb_inter_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + u8 bInterfaceNumber; // Number of this interface (0 based). + u8 bAlternateSetting; // Value of this alternate interface setting. + u8 bNumEndpoints; // Number of endpoints in this interface. + u8 bInterfaceClass; // Class code (assigned by the USB-IF). + u8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + u8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF). + u8 iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) usb_inter_descr_t; + +/* HID descriptor structure */ +typedef struct _usb_hid_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_HID). + u16 bcdHID; // HID class specification release + u8 bCountryCode; // Country code. + u8 bNumDescriptors; // Number of descriptors. + u8 bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT). + u16 bDescriptorLength; // Report descriptor length. +} __attribute__((packed)) usb_hid_descr_t; + +/* Endpoint descriptor structure */ +typedef struct _usb_ep_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + u8 bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN). + u8 bmAttributes; // Endpoint transfer type. + u16 wMaxPacketSize; // Maximum packet size. + u8 bInterval; // Polling interval in frames. For Interrupt and Isochronous data transfer only. +} __attribute__((packed)) usb_ep_descr_t; + +typedef struct _usb_cfg_simple_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_simple_descr_t; + +typedef struct _usb_cfg_hid_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_hid_descr_t hid; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_hid_descr_t; + +typedef struct _usb_dev_bot_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT) + u16 wTotalLength; // Size of this descriptor in bytes. + u8 bNumDeviceCaps; // Number of device capabilities in this descriptor. + + /* Device Capability USB 2.0 Extension Descriptor */ + /* Needed for a USB2.10 device. */ + u8 bLengthCap0; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap0; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap0; // USB2: 2. + u32 bmAttributesCap0; // bit1: Link Power Management (LPM). + + u8 bLengthCap1; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap1; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap1; // USB3: 3. + u8 bmAttributesCap1; // bit1: Latency Tolerance Messaging (LTM). + u16 wSpeedsSupported; // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed. + u8 bFunctionalitySupport; // Lowest speed at which all the functionality is available. 1: Full speed and above. + u8 bU1DevExitLat; // USB3.0 U1 exit latency. + u16 wU2DevExitLat; // USB3.0 U2 exit latency. + +} __attribute__((packed)) usb_dev_bot_t; + +/* Microsoft OS String descriptor structure */ +typedef struct _usb_ms_os_descr_t +{ + u8 bLength; // 0x12 + u8 bDescriptorType; // 3 + u16 wSignature[7]; // "MSFT100" UTF16 LE + u8 bVendorCode; // + u8 bPadding; +} __attribute__((packed)) usb_ms_os_descr_t; + +/* Microsoft Compatible ID Feature descriptor structure */ +typedef struct _usb_ms_cid_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wCompatibilityId; + u8 bSections; + u8 bReserved0[7]; + u8 bInterfaceNumber; + u8 bReserved1; + u8 bCompatibleId[8]; + u8 bSubCompatibleId[8]; + u8 bReserved2[6]; +} __attribute__((packed)) usb_ms_cid_descr_t; + +/* Microsoft Extended Properties Feature descriptor structure */ +typedef struct _usb_ms_ext_prop_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wExtendedProperty; + u16 wSections; + u32 dPropertySize; + u32 dPropertyType; + u16 wPropertyNameLength; + u16 wPropertyName[22]; // UTF16 LE + u32 dPropertyDataLength; + u16 wPropertyData[2]; // UTF16 LE +} __attribute__((packed)) usb_ms_ext_prop_descr_t; + +typedef struct _usb_desc_t +{ + usb_dev_descr_t *dev; + usb_dev_qual_descr_t *dev_qual; + usb_cfg_simple_descr_t *cfg; + usb_cfg_simple_descr_t *cfg_other; + usb_dev_bot_t *dev_bot; + u8 *vendor; + u8 *product; + u8 *serial; + u8 *lang_id; + usb_ms_os_descr_t *ms_os; + usb_ms_cid_descr_t *ms_cid; + usb_ms_ext_prop_descr_t *mx_ext; +} usb_desc_t; + +#endif diff --git a/bdk/usb/usb_descriptors.h b/bdk/usb/usb_descriptors.c similarity index 65% rename from bdk/usb/usb_descriptors.h rename to bdk/usb/usb_descriptors.c index 74556f8..389a70d 100644 --- a/bdk/usb/usb_descriptors.h +++ b/bdk/usb/usb_descriptors.c @@ -1,7 +1,7 @@ /* * USB 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 * under the terms and conditions of the GNU General Public License, @@ -16,224 +16,10 @@ * along with this program. If not, see . */ -#ifndef _USB_DESCRIPTORS_H_ -#define _USB_DESCRIPTORS_H_ - +#include #include -typedef enum { - USB_DESCRIPTOR_DEVICE = 1, - USB_DESCRIPTOR_CONFIGURATION = 2, - USB_DESCRIPTOR_STRING = 3, - USB_DESCRIPTOR_INTERFACE = 4, - USB_DESCRIPTOR_ENDPOINT = 5, - USB_DESCRIPTOR_DEVICE_QUALIFIER = 6, - USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, - USB_DESCRIPTOR_INTERFACE_POWER = 8, - USB_DESCRIPTOR_INTERFACE_OTG = 9, - USB_DESCRIPTOR_DEVICE_BINARY_OBJECT = 15, - USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP = 16, - USB_DESCRIPTOR_HID = 33, - USB_DESCRIPTOR_HID_REPORT = 34 -} usb_desc_type_t; - -typedef enum { - USB_DESCRIPTOR_MS_COMPAT_ID = 4, - USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5 -} usb_vendor_desc_type_t; - -typedef enum { - USB_ATTR_REMOTE_WAKE_UP = 0x20, - USB_ATTR_SELF_POWERED = 0x40, - USB_ATTR_BUS_POWERED_RSVD = 0x80 -} usb_cfg_attr_type_t; - -typedef enum -{ - USB_EP_TYPE_CTRL = 0, - USB_EP_TYPE_ISO = 1, - USB_EP_TYPE_BULK = 2, - USB_EP_TYPE_INTR = 3 -} usb_cfg_ep_type_t; - -/* Device descriptor structure */ -typedef struct _usb_dev_descr_t -{ - u8 bLength; // Size of this descriptor in bytes. - u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE) - u16 bcdUSB; // USB Spec. Release number (2.1). - u8 bDeviceClass; // Class is specified in the interface descriptor. - u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. - u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. - u8 bMaxPacketSize; // Maximum packet size for EP0. - u16 idVendor; // Vendor ID assigned by USB forum. - u16 idProduct; // Product ID assigned by Organization. - u16 bcdDevice; // Device Release number in BCD. - u8 iManufacturer; // Index of String descriptor describing Manufacturer. - u8 iProduct; // Index of String descriptor describing Product. - u8 iSerialNumber; // Index of String descriptor describing Serial number. - u8 bNumConfigs; // Number of possible configuration. -} __attribute__((packed)) usb_dev_descr_t; - -/* Device Qualigier descriptor structure */ -typedef struct _usb_dev_qual_descr_t -{ - u8 bLength; // Size of this descriptor in bytes. - u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER) - u16 bcdUSB; // USB Spec. Release number (2.1). - u8 bDeviceClass; // Class is specified in the interface descriptor. - u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. - u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. - u8 bMaxPacketSize; // Maximum packet size for EP0. - u8 bNumOtherConfigs; // Number of possible other-speed configurations. - u8 bReserved; // Reserved for future use, must be zero -} __attribute__((packed)) usb_dev_qual_descr_t; - -/* Configuration descriptor structure */ -typedef struct _usb_cfg_descr_t -{ - u8 bLength; // Length of this descriptor. - u8 bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). - u16 wTotalLength; // Total length of all descriptors for this configuration. - u8 bNumInterfaces; // Number of interfaces in this configuration. - u8 bConfigurationValue; // Value of this configuration (1 based). - u8 iConfiguration; // Index of String Descriptor describing the configuration. - u8 bmAttributes; // Configuration characteristics. - u8 bMaxPower; // Maximum power consumed by this configuration. -} __attribute__((packed)) usb_cfg_descr_t; - -/* Interface descriptor structure */ -typedef struct _usb_inter_descr_t -{ - u8 bLength; // Length of this descriptor. - u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). - u8 bInterfaceNumber; // Number of this interface (0 based). - u8 bAlternateSetting; // Value of this alternate interface setting. - u8 bNumEndpoints; // Number of endpoints in this interface. - u8 bInterfaceClass; // Class code (assigned by the USB-IF). - u8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF). - u8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF). - u8 iInterface; // Index of String Descriptor describing the interface. -} __attribute__((packed)) usb_inter_descr_t; - -/* HID descriptor structure */ -typedef struct _usb_hid_descr_t -{ - u8 bLength; // Length of this descriptor. - u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_HID). - u16 bcdHID; // HID class specification release - u8 bCountryCode; // Country code. - u8 bNumDescriptors; // Number of descriptors. - u8 bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT). - u16 bDescriptorLength; // Report descriptor length. -} __attribute__((packed)) usb_hid_descr_t; - -/* Endpoint descriptor structure */ -typedef struct _usb_ep_descr_t -{ - u8 bLength; // Length of this descriptor. - u8 bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). - u8 bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN). - u8 bmAttributes; // Endpoint transfer type. - u16 wMaxPacketSize; // Maximum packet size. - u8 bInterval; // Polling interval in frames. For Interrupt and Isochronous data transfer only. -} __attribute__((packed)) usb_ep_descr_t; - -typedef struct _usb_cfg_simple_descr_t -{ - usb_cfg_descr_t config; - usb_inter_descr_t interface; - usb_ep_descr_t endpoint[2]; -} __attribute__((packed)) usb_cfg_simple_descr_t; - -typedef struct _usb_cfg_hid_descr_t -{ - usb_cfg_descr_t config; - usb_inter_descr_t interface; - usb_hid_descr_t hid; - usb_ep_descr_t endpoint[2]; -} __attribute__((packed)) usb_cfg_hid_descr_t; - -typedef struct _usb_dev_bot_t -{ - u8 bLength; // Size of this descriptor in bytes. - u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT) - u16 wTotalLength; // Size of this descriptor in bytes. - u8 bNumDeviceCaps; // Number of device capabilities in this descriptor. - - /* Device Capability USB 2.0 Extension Descriptor */ - /* Needed for a USB2.10 device. */ - u8 bLengthCap0; // Size of this capability descriptor in bytes. - u8 bDescriptorTypeCap0; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) - u8 bDevCapabilityTypeCap0; // USB2: 2. - u32 bmAttributesCap0; // bit1: Link Power Management (LPM). - - u8 bLengthCap1; // Size of this capability descriptor in bytes. - u8 bDescriptorTypeCap1; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) - u8 bDevCapabilityTypeCap1; // USB3: 3. - u8 bmAttributesCap1; // bit1: Latency Tolerance Messaging (LTM). - u16 wSpeedsSupported; // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed. - u8 bFunctionalitySupport; // Lowest speed at which all the functionality is available. 1: Full speed and above. - u8 bU1DevExitLat; // USB3.0 U1 exit latency. - u16 wU2DevExitLat; // USB3.0 U2 exit latency. - -} __attribute__((packed)) usb_dev_bot_t; - -/* Microsoft OS String descriptor structure */ -typedef struct _usb_ms_os_descr_t -{ - u8 bLength; // 0x12 - u8 bDescriptorType; // 3 - u16 wSignature[7]; // "MSFT100" UTF16 LE - u8 bVendorCode; // - u8 bPadding; -} __attribute__((packed)) usb_ms_os_descr_t; - -/* Microsoft Compatible ID Feature descriptor structure */ -typedef struct _usb_ms_cid_descr_t -{ - u32 dLength; - u16 wVersion; - u16 wCompatibilityId; - u8 bSections; - u8 bReserved0[7]; - u8 bInterfaceNumber; - u8 bReserved1; - u8 bCompatibleId[8]; - u8 bSubCompatibleId[8]; - u8 bReserved2[6]; -} __attribute__((packed)) usb_ms_cid_descr_t; - -/* Microsoft Extended Properties Feature descriptor structure */ -typedef struct _usb_ms_ext_prop_descr_t -{ - u32 dLength; - u16 wVersion; - u16 wExtendedProperty; - u16 wSections; - u32 dPropertySize; - u32 dPropertyType; - u16 wPropertyNameLength; - u16 wPropertyName[22]; // UTF16 LE - u32 dPropertyDataLength; - u16 wPropertyData[2]; // UTF16 LE -} __attribute__((packed)) usb_ms_ext_prop_descr_t; - -typedef struct _usb_desc_t -{ - usb_dev_descr_t *dev; - usb_dev_qual_descr_t *dev_qual; - usb_cfg_simple_descr_t *cfg; - usb_cfg_simple_descr_t *cfg_other; - usb_dev_bot_t *dev_bot; - u8 *vendor; - u8 *product; - usb_ms_os_descr_t *ms_os; - usb_ms_cid_descr_t *ms_cid; - usb_ms_ext_prop_descr_t *mx_ext; -} usb_desc_t; - -usb_dev_descr_t usb_device_descriptor_ums = +static usb_dev_descr_t usb_device_descriptor_ums = { .bLength = 18, .bDescriptorType = USB_DESCRIPTOR_DEVICE, @@ -251,7 +37,7 @@ usb_dev_descr_t usb_device_descriptor_ums = .bNumConfigs = 1 }; -usb_dev_qual_descr_t usb_device_qualifier_descriptor = +static usb_dev_qual_descr_t usb_device_qualifier_descriptor = { .bLength = 10, .bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER, @@ -264,7 +50,7 @@ usb_dev_qual_descr_t usb_device_qualifier_descriptor = .bReserved = 0x00 }; -usb_cfg_simple_descr_t usb_configuration_descriptor_ums = +static usb_cfg_simple_descr_t usb_configuration_descriptor_ums = { /* Configuration descriptor structure */ .config.bLength = 9, @@ -304,7 +90,7 @@ usb_cfg_simple_descr_t usb_configuration_descriptor_ums = .endpoint[1].bInterval = 0x00 }; -usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = +static usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = { /* Other Speed Configuration descriptor structure */ .config.bLength = 9, @@ -344,7 +130,7 @@ usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = .endpoint[1].bInterval = 0 }; -usb_dev_bot_t usb_device_binary_object_descriptor = +static usb_dev_bot_t usb_device_binary_object_descriptor = { .bLength = 5, .bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT, @@ -369,20 +155,33 @@ usb_dev_bot_t usb_device_binary_object_descriptor = .wU2DevExitLat = 0 }; -u8 usb_vendor_string_descriptor_ums[32] = +static u8 usb_lang_id_string_descriptor[4] = +{ + 4, 3, + 0x09, 0x04 +}; + +static u8 usb_serial_string_descriptor[26] = +{ + 26, 0x03, + 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, + '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 +}; + +static u8 usb_vendor_string_descriptor_ums[32] = { 26, 0x03, 'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0, 'D', 0, 'i', 0, 's', 0, 'k', 0 }; -u8 usb_product_string_descriptor_ums[22] = +static u8 usb_product_string_descriptor_ums[22] = { 8, 0x03, 'U', 0, 'M', 0, 'S', 0 }; -usb_ms_os_descr_t usb_ms_os_descriptor = +static usb_ms_os_descr_t usb_ms_os_descriptor = { .bLength = 0x28, .bDescriptorType = 0x03, @@ -396,7 +195,7 @@ usb_ms_os_descr_t usb_ms_os_descriptor = .bVendorCode = 0x99, }; -usb_ms_cid_descr_t usb_ms_cid_descriptor = +static usb_ms_cid_descr_t usb_ms_cid_descriptor = { .dLength = 0x28, .wVersion = 0x100, @@ -413,7 +212,7 @@ usb_ms_cid_descr_t usb_ms_cid_descriptor = .bCompatibleId[5] = 'B', }; -usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = +static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = { .dLength = 0x48, .wVersion = 0x100, @@ -452,7 +251,7 @@ usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = .wPropertyData[1] = 0x10, }; -usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = +static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = { .dLength = 7, .wVersion = 0x100, @@ -460,7 +259,7 @@ usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = .wSections = 0, }; -usb_dev_descr_t usb_device_descriptor_hid_jc = +static usb_dev_descr_t usb_device_descriptor_hid_jc = { .bLength = 18, .bDescriptorType = USB_DESCRIPTOR_DEVICE, @@ -478,7 +277,7 @@ usb_dev_descr_t usb_device_descriptor_hid_jc = .bNumConfigs = 1 }; -usb_dev_descr_t usb_device_descriptor_hid_touch = +static usb_dev_descr_t usb_device_descriptor_hid_touch = { .bLength = 18, .bDescriptorType = USB_DESCRIPTOR_DEVICE, @@ -496,75 +295,6 @@ usb_dev_descr_t usb_device_descriptor_hid_touch = .bNumConfigs = 1 }; -usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = -{ - /* Configuration descriptor structure */ - .config.bLength = 9, - .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, - .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), - .config.bNumInterfaces = 0x01, - .config.bConfigurationValue = 0x01, - .config.iConfiguration = 0x00, - .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, - .config.bMaxPower = 32 / 2, - - /* Interface descriptor structure */ - .interface.bLength = 9, - .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, - .interface.bInterfaceNumber = 0, - .interface.bAlternateSetting = 0, - .interface.bNumEndpoints = 2, - .interface.bInterfaceClass = 0x03, // Human Interface Device Class. - .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. - .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. - .interface.iInterface = 0x00, - - .hid.bLength = 9, - .hid.bDescriptorType = USB_DESCRIPTOR_HID, - .hid.bcdHID = 0x110, - .hid.bCountryCode = 0, - .hid.bNumDescriptors = 1, - .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, - .hid.bDescriptorLength = 0x43, - - /* Endpoint descriptor structure EP1 IN */ - .endpoint[0].bLength = 7, - .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, - .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. - .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, - .endpoint[0].wMaxPacketSize = 0x200, - .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. - - /* Endpoint descriptor structure EP1 OUT */ - .endpoint[1].bLength = 7, - .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, - .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. - .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, - .endpoint[1].wMaxPacketSize = 0x200, - .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. -}; - -u8 usb_vendor_string_descriptor_hid[22] = -{ - 16, 0x03, - 'N', 0, 'y', 0, 'x', 0, ' ', 0, - 'U', 0, 'S', 0, 'B', 0 -}; - -u8 usb_product_string_descriptor_hid_jc[24] = -{ - 24, 0x03, - 'N', 0, 'y', 0, 'x', 0, ' ', 0, - 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 -}; - -u8 usb_product_string_descriptor_hid_touch[26] = -{ - 26, 0x03, - 'N', 0, 'y', 0, 'x', 0, ' ', 0, - 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 -}; - u8 hid_report_descriptor_jc[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop), @@ -602,6 +332,8 @@ u8 hid_report_descriptor_jc[] = 0xc0 // END_COLLECTION(), }; +u32 hid_report_descriptor_jc_size = sizeof(hid_report_descriptor_jc); + u8 hid_report_descriptor_touch[] = { 0x05, 0x0d, // USAGE_PAGE (Digitizers) @@ -658,8 +390,78 @@ u8 hid_report_descriptor_touch[] = 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION }; +u32 hid_report_descriptor_touch_size = sizeof(hid_report_descriptor_touch); -usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = +static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x110, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = sizeof(hid_report_descriptor_jc), + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 8ms on HS. +}; + +static u8 usb_vendor_string_descriptor_hid[22] = +{ + 16, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'U', 0, 'S', 0, 'B', 0 +}; + +static u8 usb_product_string_descriptor_hid_jc[24] = +{ + 24, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 +}; + +static u8 usb_product_string_descriptor_hid_touch[26] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 +}; + +static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = { /* Configuration descriptor structure */ .config.bLength = 9, @@ -696,7 +498,7 @@ usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, .endpoint[0].wMaxPacketSize = 0x200, - .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. + .endpoint[0].bInterval = 3, // 4ms on HS. /* Endpoint descriptor structure EP1 OUT */ .endpoint[1].bLength = 7, @@ -704,7 +506,7 @@ usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, .endpoint[1].wMaxPacketSize = 0x200, - .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. + .endpoint[1].bInterval = 3 // 4ms on HS. }; usb_desc_t usb_gadget_ums_descriptors = @@ -716,6 +518,8 @@ usb_desc_t usb_gadget_ums_descriptors = .dev_bot = &usb_device_binary_object_descriptor, .vendor = usb_vendor_string_descriptor_ums, .product = usb_product_string_descriptor_ums, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, .ms_os = &usb_ms_os_descriptor, .ms_cid = &usb_ms_cid_descriptor, .mx_ext = &usb_ms_ext_prop_descriptor_ums @@ -730,6 +534,8 @@ usb_desc_t usb_gadget_hid_jc_descriptors = .dev_bot = &usb_device_binary_object_descriptor, .vendor = usb_vendor_string_descriptor_hid, .product = usb_product_string_descriptor_hid_jc, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, .ms_os = &usb_ms_os_descriptor, .ms_cid = &usb_ms_cid_descriptor, .mx_ext = &usb_ms_ext_prop_descriptor_hid @@ -744,9 +550,9 @@ usb_desc_t usb_gadget_hid_touch_descriptors = .dev_bot = &usb_device_binary_object_descriptor, .vendor = usb_vendor_string_descriptor_hid, .product = usb_product_string_descriptor_hid_touch, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, .ms_os = &usb_ms_os_descriptor, .ms_cid = &usb_ms_cid_descriptor, .mx_ext = &usb_ms_ext_prop_descriptor_hid }; - -#endif diff --git a/bdk/usb/usb_gadget_hid.c b/bdk/usb/usb_gadget_hid.c index e26dd9a..3437b40 100644 --- a/bdk/usb/usb_gadget_hid.c +++ b/bdk/usb/usb_gadget_hid.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -67,6 +69,7 @@ typedef struct _jc_cal_t } jc_cal_t; static jc_cal_t jc_cal_ctx; +static usb_ops_t usb_ops; static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad) { @@ -306,16 +309,16 @@ static bool _fts_touch_read(touchpad_report_t *rpt) static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len) { - u8 status = usb_device_write_ep1_in((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, true); - - if (status == 26) + u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED); + if (status == USB_ERROR_XFER_ERROR) { - usbs->set_text(usbs->label, "#C7EA46 Status:# Error EP IN"); - usbd_flush_endpoint(3); + usbs->set_text(usbs->label, "#FFDD00 Error:# EP IN transfer!"); + if (usb_ops.usbd_flush_endpoint) + usb_ops.usbd_flush_endpoint(USB_EP_BULK_IN); } // Linux mitigation: If timed out, clear status. - if (status == 3) + if (status == USB_ERROR_TIMEOUT) return 0; return status; @@ -350,6 +353,12 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs) u32 gadget_type; u32 polling_time; + // Get USB Controller ops. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + usb_device_get_ops(&usb_ops); + else + xusb_device_get_ops(&usb_ops); + if (usbs->type == USB_HID_GAMEPAD) { polling_time = 8000; @@ -363,21 +372,21 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs) usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); - if (usb_device_init()) + if (usb_ops.usb_device_init()) { - usbd_end(false, true); + usb_ops.usbd_end(false, true); return 1; } usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection"); // Initialize Control Endpoint. - if (usb_device_ep0_initialize(gadget_type)) + if (usb_ops.usb_device_enumerate(gadget_type)) goto error; usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for HID report request"); - if (usb_device_get_hid_report()) + if (usb_ops.usb_device_class_send_hid_report()) goto error; usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation"); @@ -400,11 +409,11 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs) } // Check for suspended USB in case the cable was pulled. - if (usb_device_get_suspended()) + if (usb_ops.usb_device_get_suspended()) break; // Disconnected. // Handle control endpoint. - usbd_handle_ep0_pending_control_transfer(); + usb_ops.usbd_handle_ep0_ctrl_setup(); // Wait max gadget timing. timer = get_tmr_us() - timer; @@ -422,11 +431,11 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs) goto exit; error: - usbs->set_text(usbs->label, "#C7EA46 Status:# Timed out or canceled"); + usbs->set_text(usbs->label, "#FFDD00 Error:# Timed out or canceled"); res = 1; exit: - usbd_end(true, false); + usb_ops.usbd_end(true, false); return res; } diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c index 01ab237..97deeb5 100644 --- a/bdk/usb/usb_gadget_ums.c +++ b/bdk/usb/usb_gadget_ums.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -198,7 +200,6 @@ typedef struct _usbd_gadget_ums_t { u32 lun_idx; // lun index logical_unit_t lun; - u32 bulk_out_maxpacket; // 512 enum ums_state state; // For exception handling. enum data_direction data_dir; @@ -215,12 +216,15 @@ typedef struct _usbd_gadget_ums_t { int can_stall; u32 timeouts; + bool xusb; void (*system_maintenance)(bool); void *label; void (*set_text)(void *, const char *); } usbd_gadget_ums_t; +static usb_ops_t usb_ops; + static inline void put_array_le_to_be16(u16 val, void *p) { u8 *_p = p; @@ -271,7 +275,7 @@ static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state) static void ums_handle_ep0_ctrl(usbd_gadget_ums_t *ums) { - if (usbd_handle_ep0_pending_control_transfer()) + if (usb_ops.usbd_handle_ep0_ctrl_setup()) raise_exception(ums, UMS_STATE_PROTOCOL_RESET); } @@ -284,46 +288,56 @@ static int ums_wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums) static int ums_set_stall(u32 ep) { - usbd_set_ep_stall(ep, 1); + usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_STALL); return 0; } static int ums_clear_stall(u32 ep) { - usbd_set_ep_stall(ep, 0); + usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_CLEAR); return 0; } +static void ums_flush_endpoint(u32 ep) +{ + if (usb_ops.usbd_flush_endpoint) + usb_ops.usbd_flush_endpoint(ep); +} + static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync) { if (ep == bulk_ctxt->bulk_in) { - bulk_ctxt->bulk_in_status = usb_device_write_ep1_in( + bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_write( bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, &bulk_ctxt->bulk_in_length_actual, sync); - if (bulk_ctxt->bulk_in_status == 26) + if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) { - ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); - usbd_flush_endpoint(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#FFDD00 Error:# EP IN transfer!"); + ums_flush_endpoint(bulk_ctxt->bulk_in); } + else if (bulk_ctxt->bulk_in_status == USB2_ERROR_XFER_NOT_ALIGNED) + ums->set_text(ums->label, "#FFDD00 Error:# EP IN Buffer not aligned!"); if (sync) bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; } else { - bulk_ctxt->bulk_out_status = usb_device_read_ep1_out( + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read( bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, &bulk_ctxt->bulk_out_length_actual, sync); - if (bulk_ctxt->bulk_out_status == 26) + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { - ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); - usbd_flush_endpoint(bulk_ctxt->bulk_out); + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + ums_flush_endpoint(bulk_ctxt->bulk_out); } + else if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_NOT_ALIGNED) + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT Buffer not aligned!"); if (sync) bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; @@ -332,14 +346,14 @@ static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { - bulk_ctxt->bulk_out_status = usb_device_read_ep1_out_big_reads( + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read_big( bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, &bulk_ctxt->bulk_out_length_actual); - if (bulk_ctxt->bulk_out_status == 26) + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { - ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); - usbd_flush_endpoint(bulk_ctxt->bulk_out); + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + ums_flush_endpoint(bulk_ctxt->bulk_out); } bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; @@ -349,24 +363,26 @@ static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, { if (ep == bulk_ctxt->bulk_in) { - bulk_ctxt->bulk_in_status = usb_device_ep1_in_writing_finish(&bulk_ctxt->bulk_in_length_actual); + bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_writing_finish( + &bulk_ctxt->bulk_in_length_actual); - if (bulk_ctxt->bulk_in_status == 26) + if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) { - ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); - usbd_flush_endpoint(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#FFDD00 Error:# EP IN transfer!"); + ums_flush_endpoint(bulk_ctxt->bulk_in); } bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; } else { - bulk_ctxt->bulk_out_status = usb_device_ep1_out_reading_finish(&bulk_ctxt->bulk_out_length_actual); + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish( + &bulk_ctxt->bulk_out_length_actual, 1000000); - if (bulk_ctxt->bulk_out_status == 26) + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { - ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); - usbd_flush_endpoint(bulk_ctxt->bulk_out); + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + ums_flush_endpoint(bulk_ctxt->bulk_out); } bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; @@ -485,7 +501,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // If an error occurred, report it and its position. if (!amount) { - ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Read"); + ums->set_text(ums->label, "#FFDD00 Error:# SDMMC Read!"); ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; ums->lun.sense_data_info = lba_offset; ums->lun.info_valid = 1; @@ -497,7 +513,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) break; // Start the USB transfer. - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, false); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_START); first_read = false; // Increment our buffer to read new data. @@ -568,7 +584,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (usb_lba_offset >= ums->lun.num_sectors) //////////Check if it works with concurrency { - ums->set_text(ums->label, "#C7EA46 Status:# Write Error - Past last sector"); + ums->set_text(ums->label, "#FFDD00 Error:# Write - Past last sector!"); amount_left_to_req = 0; ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ums->lun.sense_data_info = usb_lba_offset; @@ -596,7 +612,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) ums->lun.sense_data = SS_COMMUNICATION_FAILURE; ums->lun.sense_data_info = lba_offset; ums->lun.info_valid = 1; - sprintf(txt_buf, "#C7EA46 Status:# Write Error - Comm failure %d", bulk_ctxt->bulk_out_status); + sprintf(txt_buf, "#FFDD00 Error:# Write - Comm failure %d!", bulk_ctxt->bulk_out_status); ums->set_text(ums->label, txt_buf); break; } @@ -634,7 +650,7 @@ DPRINTF("file write %X @ %X\n", amount, lba_offset); /* If an error occurred, report it and its position */ if (!amount) { - ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Write"); + ums->set_text(ums->label, "#FFDD00 Error:# SDMMC Write!"); ums->lun.sense_data = SS_WRITE_ERROR; ums->lun.sense_data_info = lba_offset; ums->lun.info_valid = 1; @@ -645,7 +661,7 @@ DPRINTF("file write %X @ %X\n", amount, lba_offset); // Did the host decide to stop early? if (bulk_ctxt->bulk_out_length_actual < bulk_ctxt->bulk_out_length) { - ums->set_text(ums->label, "#C7EA46 Status:# Empty Write"); + ums->set_text(ums->label, "#FFDD00 Error:# Empty Write!"); ums->short_packet_received = 1; break; } @@ -699,7 +715,7 @@ DPRINTF("File read %X @ %X\n", amount, lba_offset); if (!amount) { - ums->set_text(ums->label, "#C7EA46 Status:# Error file verify"); + ums->set_text(ums->label, "#FFDD00 Error:# File verify!"); ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; ums->lun.sense_data_info = lba_offset; ums->lun.info_valid = 1; @@ -943,7 +959,7 @@ static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) buf += 4; } else // SC_MODE_SENSE_10. - { + { buf[3] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. buf += 8; } @@ -1158,7 +1174,7 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", ums->cmnd[1] &= 0x1F; // Mask away the LUN. for (u32 i = 1; i < cmnd_size; ++i) { - if (ums->cmnd[i] && !(mask & (1 << i))) + if (ums->cmnd[i] && !(mask & BIT(i))) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; @@ -1382,7 +1398,7 @@ static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); bulk_ctxt->bulk_in_length = nsend; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); ums->usb_amount_left -= nsend; current_len_to_keep = 0; } @@ -1400,7 +1416,7 @@ static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); bulk_ctxt->bulk_out_length = amount; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED); ums->usb_amount_left -= amount; return 0; @@ -1412,7 +1428,7 @@ static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // A short packet or an error ends everything. if (bulk_ctxt->bulk_out_length_actual != bulk_ctxt->bulk_out_length || - bulk_ctxt->bulk_out_status != 0) + bulk_ctxt->bulk_out_status != USB_RES_OK) { raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); return -4; // Interrupted system call @@ -1436,7 +1452,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums_set_stall(bulk_ctxt->bulk_out); rc = ums_set_stall(bulk_ctxt->bulk_in); - ums->set_text(ums->label, "#C7EA46 Status:# Direction unknown. Stalled both EP"); + ums->set_text(ums->label, "#FFDD00 Error:# Direction unknown. Stalled both EP!"); } // Else do nothing. break; @@ -1447,7 +1463,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // If there's no residue, simply send the last buffer. if (!ums->residue) { - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); /* For Bulk-only, if we're allowed to stall then send the * short packet and halt the bulk-in endpoint. If we can't @@ -1455,9 +1471,9 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) } else if (ums->can_stall) { - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); rc = ums_set_stall(bulk_ctxt->bulk_in); - ums->set_text(ums->label, "#C7EA46 Status:# Residue. Stalled EP IN"); + ums->set_text(ums->label, "#FFDD00 Error:# Residue. Stalled EP IN!"); } else rc = pad_with_zeros(ums, bulk_ctxt); @@ -1523,26 +1539,28 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) DPRINTF("USB: EP timeout\n"); // In case we disconnected, exit UMS. // Raise timeout if removable and didn't got a unit ready command inside 4s. - if (bulk_ctxt->bulk_out_status == 28 || - (bulk_ctxt->bulk_out_status == 3 && ums->lun.removable && !ums->lun.prevent_medium_removal)) + if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_EP_DISABLED || + (bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT && ums->lun.removable && !ums->lun.prevent_medium_removal)) { - if (bulk_ctxt->bulk_out_status == 3) + if (bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT) { - if (usb_device_get_port_status() == 0x885) + if (usb_ops.usb_device_get_port_in_sleep()) { ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep"); - ums->timeouts += 10; + ums->timeouts += 14; } - else + else if (!ums->xusb) // Timeout only on USB2. + { + ums->timeouts += 4; DPRINTF("USB: EP removable\n"); + } } else { gfx_printf("USB: EP disabled\n"); msleep(500); + ums->timeouts += 4; } - - ums->timeouts += 4; } if (ums->lun.unmounted) @@ -1592,7 +1610,7 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums_set_stall(bulk_ctxt->bulk_out); ums_set_stall(bulk_ctxt->bulk_in); - ums->set_text(ums->label, "#C7EA46 Status:# CBW unknown - Stalled both EP"); + ums->set_text(ums->label, "#FFDD00 Error:# CBW unknown - Stalled both EP!"); } return -22; // Invalid argument. @@ -1634,7 +1652,7 @@ static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; /* Queue a request to read a Bulk-only CBW */ - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED); /* We will drain the buffer in software, which means we * can reuse it for the next filling. No need to advance @@ -1659,7 +1677,7 @@ static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (ums->phase_error) { - ums->set_text(ums->label, "#C7EA46 Status:# Phase-error"); + ums->set_text(ums->label, "#FFDD00 Error:# Phase-error!"); status = USB_STATUS_PHASE_ERROR; sd = SS_INVALID_COMMAND; } @@ -1680,7 +1698,7 @@ static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) csw->Status = status; bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); } static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -1688,8 +1706,8 @@ static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) enum ums_state old_state; /* Clear out the controller's fifos */ - usbd_flush_endpoint(bulk_ctxt->bulk_in); - usbd_flush_endpoint(bulk_ctxt->bulk_out); + ums_flush_endpoint(bulk_ctxt->bulk_in); + ums_flush_endpoint(bulk_ctxt->bulk_out); /* Reset the I/O buffer states and pointers, the SCSI * state, and the exception. Then invoke the handler. */ @@ -1764,26 +1782,32 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs) int res = 0; sdmmc_t sdmmc; sdmmc_storage_t storage; + usbd_gadget_ums_t ums = {0}; + + // Get USB Controller ops. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + usb_device_get_ops(&usb_ops); + else + { + ums.xusb = true; + xusb_device_get_ops(&usb_ops); + } usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); - if (usb_device_init()) + if (usb_ops.usb_device_init()) { - usbd_end(false, true); + usb_ops.usbd_end(false, true); return 1; } - usbd_gadget_ums_t ums; - memset(&ums, 0, sizeof(usbd_gadget_ums_t)); - - ums.bulk_out_maxpacket = usbd_get_max_pkt_length(USB_EP_BULK_IN); ums.state = UMS_STATE_NORMAL; ums.can_stall = 0; - ums.bulk_ctxt.bulk_in = 3; + ums.bulk_ctxt.bulk_in = USB_EP_BULK_IN; ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; - ums.bulk_ctxt.bulk_out = 2; + ums.bulk_ctxt.bulk_out = USB_EP_BULK_OUT; ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; // Set LUN parameters. @@ -1820,12 +1844,12 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs) ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection"); // Initialize Control Endpoint. - if (usb_device_ep0_initialize(USB_GADGET_UMS)) + if (usb_ops.usb_device_enumerate(USB_GADGET_UMS)) goto error; ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN"); - if (usb_device_get_max_lun(0)) // One device for now. + if (usb_ops.usb_device_class_send_max_lun(0)) // One device for now. goto error; ums.set_text(ums.label, "#C7EA46 Status:# Started UMS"); @@ -1878,14 +1902,14 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs) goto exit; error: - ums.set_text(ums.label, "#C7EA46 Status:# Timed out or canceled"); + ums.set_text(ums.label, "#FFDD00 Error:# Timed out or canceled!"); res = 1; exit: if (ums.lun.type == MMC_EMMC) sdmmc_storage_end(ums.lun.storage); - usbd_end(true, false); + usb_ops.usbd_end(true, false); return res; } diff --git a/bdk/usb/usb_t210.h b/bdk/usb/usb_t210.h index d670317..4d67c69 100644 --- a/bdk/usb/usb_t210.h +++ b/bdk/usb/usb_t210.h @@ -1,7 +1,7 @@ /* - * USB driver for Tegra X1 + * Enhanced & eXtensible USB device (EDCI & XDCI) 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 * under the terms and conditions of the GNU General Public License, @@ -21,14 +21,16 @@ #include +/* EHCI USB */ + /* General USB registers */ #define USB1_IF_USB_SUSP_CTRL 0x400 -#define SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV (1 << 3) -#define SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV (1 << 4) -#define SUSP_CTRL_USB_PHY_CLK_VALID (1 << 7) -#define SUSP_CTRL_UTMIP_RESET (1 << 11) -#define SUSP_CTRL_UTMIP_PHY_ENB (1 << 12) -#define SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET (1 << 25) +#define SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV BIT(3) +#define SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV BIT(4) +#define SUSP_CTRL_USB_PHY_CLK_VALID BIT(7) +#define SUSP_CTRL_UTMIP_RESET BIT(11) +#define SUSP_CTRL_UTMIP_PHY_ENB BIT(12) +#define SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET BIT(25) #define USB1_IF_USB_PHY_VBUS_SENSORS 0x404 #define USB1_UTMIP_XCVR_CFG0 0x808 #define USB1_UTMIP_BIAS_CFG0 0x80C @@ -37,6 +39,9 @@ #define USB1_UTMIP_TX_CFG0 0x820 #define USB1_UTMIP_MISC_CFG1 0x828 #define USB1_UTMIP_DEBOUNCE_CFG0 0x82C +#define USB1_UTMIP_BAT_CHRG_CFG0 0x830 +#define BAT_CHRG_CFG0_PWRDOWN_CHRG BIT(0) +#define BAT_CHRG_CFG0_OP_SRC_EN BIT(3) #define USB1_UTMIP_SPARE_CFG0 0x834 #define USB1_UTMIP_XCVR_CFG1 0x838 #define USB1_UTMIP_BIAS_CFG1 0x83C @@ -46,38 +51,38 @@ /* USB Queue Head Descriptor */ #define USB2_QH_USB2D_QH_EP_BASE (USB_BASE + 0x1000) -#define USB_QHD_EP_CAP_IOS_ENABLE (1 << 15) +#define USB_QHD_EP_CAP_IOS_ENABLE BIT(15) #define USB_QHD_EP_CAP_MAX_PKT_LEN_MASK 0x7FF -#define USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS (1 << 29) +#define USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS BIT(29) #define USB_QHD_EP_CAP_MULTI_NON_ISO (0 << 30) #define USB_QHD_EP_CAP_MULTI_1 (1 << 30) #define USB_QHD_EP_CAP_MULTI_2 (2 << 30) #define USB_QHD_EP_CAP_MULTI_3 (3 << 30) -#define USB_QHD_TOKEN_XFER_ERROR (1 << 3) -#define USB_QHD_TOKEN_BUFFER_ERROR (1 << 5) -#define USB_QHD_TOKEN_HALTED (1 << 6) -#define USB_QHD_TOKEN_ACTIVE (1 << 7) +#define USB_QHD_TOKEN_XFER_ERROR BIT(3) +#define USB_QHD_TOKEN_BUFFER_ERROR BIT(5) +#define USB_QHD_TOKEN_HALTED BIT(6) +#define USB_QHD_TOKEN_ACTIVE BIT(7) #define USB_QHD_TOKEN_MULT_OVERR_MASK (2 << 10) -#define USB_QHD_TOKEN_IRQ_ON_COMPLETE (1 << 15) +#define USB_QHD_TOKEN_IRQ_ON_COMPLETE BIT(15) #define USB_QHD_TOKEN_TOTAL_BYTES_SHIFT 16 /* USB_OTG/USB_1 controllers register bits */ -#define USB2D_PORTSC1_SUSP (1 << 7) +#define USB2D_PORTSC1_SUSP BIT(7) -#define USB2D_USBCMD_RUN (1 << 0) -#define USB2D_USBCMD_RESET (1 << 1) +#define USB2D_USBCMD_RUN BIT(0) +#define USB2D_USBCMD_RESET BIT(1) #define USB2D_USBCMD_ITC_MASK (0xFF << 16) -#define USB2D_USBSTS_UI (1 << 0) -#define USB2D_USBSTS_UEI (1 << 1) -#define USB2D_USBSTS_PCI (1 << 2) -#define USB2D_USBSTS_FRI (1 << 3) -#define USB2D_USBSTS_SEI (1 << 4) -#define USB2D_USBSTS_AAI (1 << 5) -#define USB2D_USBSTS_URI (1 << 6) -#define USB2D_USBSTS_SRI (1 << 7) -#define USB2D_USBSTS_SLI (1 << 8) +#define USB2D_USBSTS_UI BIT(0) +#define USB2D_USBSTS_UEI BIT(1) +#define USB2D_USBSTS_PCI BIT(2) +#define USB2D_USBSTS_FRI BIT(3) +#define USB2D_USBSTS_SEI BIT(4) +#define USB2D_USBSTS_AAI BIT(5) +#define USB2D_USBSTS_URI BIT(6) +#define USB2D_USBSTS_SRI BIT(7) +#define USB2D_USBSTS_SLI BIT(8) #define USB2D_USBMODE_CM_MASK (3 << 0) #define USB2D_USBMODE_CM_IDLE 0 @@ -85,33 +90,33 @@ #define USB2D_USBMODE_CM_DEVICE 2 #define USB2D_USBMODE_CM_HOST 3 -#define USB2D_ENDPT_STATUS_RX_OFFSET (1 << 0) -#define USB2D_ENDPT_STATUS_TX_OFFSET (1 << 16) +#define USB2D_ENDPT_STATUS_RX_OFFSET BIT(0) +#define USB2D_ENDPT_STATUS_TX_OFFSET BIT(16) -#define USB2D_ENDPTCTRL_RX_EP_STALL (1 << 0) +#define USB2D_ENDPTCTRL_RX_EP_STALL BIT(0) #define USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL (0 << 2) #define USB2D_ENDPTCTRL_RX_EP_TYPE_ISO (1 << 2) #define USB2D_ENDPTCTRL_RX_EP_TYPE_BULK (2 << 2) #define USB2D_ENDPTCTRL_RX_EP_TYPE_INTR (3 << 2) #define USB2D_ENDPTCTRL_RX_EP_TYPE_MASK (3 << 2) -#define USB2D_ENDPTCTRL_RX_EP_INHIBIT (1 << 5) -#define USB2D_ENDPTCTRL_RX_EP_RESET (1 << 6) -#define USB2D_ENDPTCTRL_RX_EP_ENABLE (1 << 7) -#define USB2D_ENDPTCTRL_TX_EP_STALL (1 << 16) +#define USB2D_ENDPTCTRL_RX_EP_INHIBIT BIT(5) +#define USB2D_ENDPTCTRL_RX_EP_RESET BIT(6) +#define USB2D_ENDPTCTRL_RX_EP_ENABLE BIT(7) +#define USB2D_ENDPTCTRL_TX_EP_STALL BIT(16) #define USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL (0 << 18) #define USB2D_ENDPTCTRL_TX_EP_TYPE_ISO (1 << 18) #define USB2D_ENDPTCTRL_TX_EP_TYPE_BULK (2 << 18) #define USB2D_ENDPTCTRL_TX_EP_TYPE_INTR (3 << 18) #define USB2D_ENDPTCTRL_TX_EP_TYPE_MASK (3 << 18) -#define USB2D_ENDPTCTRL_TX_EP_INHIBIT (1 << 21) -#define USB2D_ENDPTCTRL_TX_EP_RESET (1 << 22) -#define USB2D_ENDPTCTRL_TX_EP_ENABLE (1 << 23) +#define USB2D_ENDPTCTRL_TX_EP_INHIBIT BIT(21) +#define USB2D_ENDPTCTRL_TX_EP_RESET BIT(22) +#define USB2D_ENDPTCTRL_TX_EP_ENABLE BIT(23) -#define USB2D_HOSTPC1_DEVLC_ASUS (1 << 17) -#define USB2D_HOSTPC1_DEVLC_PHCD (1 << 22) +#define USB2D_HOSTPC1_DEVLC_ASUS BIT(17) +#define USB2D_HOSTPC1_DEVLC_PHCD BIT(22) #define USB2D_HOSTPC1_DEVLC_PSPD_MASK (3 << 25) -#define USB2D_OTGSC_USB_ID_PULLUP (1 << 5) +#define USB2D_OTGSC_USB_ID_PULLUP BIT(5) #define USB2D_OTGSC_USB_IRQ_STS_MASK (0x7F << 16) /* USB_OTG/USB_1 controllers registers */ @@ -169,4 +174,119 @@ typedef struct _t210_usb2d_t vu32 endptctrl[16]; } t210_usb2d_t; + +/* XHCI USB */ + +/* XUSB DEV XHCI registers */ +#define XUSB_DEV_XHCI_DB 0x4 +#define XUSB_DEV_XHCI_ERSTSZ 0x8 +#define XUSB_DEV_XHCI_ERST0BALO 0x10 +#define XUSB_DEV_XHCI_ERST0BAHI 0x14 +#define XUSB_DEV_XHCI_ERST1BALO 0x18 +#define XUSB_DEV_XHCI_ERST1BAHI 0x1C +#define XUSB_DEV_XHCI_ERDPLO 0x20 +#define XHCI_ERDPLO_EHB BIT(3) +#define XUSB_DEV_XHCI_ERDPHI 0x24 +#define XUSB_DEV_XHCI_EREPLO 0x28 +#define XCHI_ECS BIT(0) +#define XUSB_DEV_XHCI_EREPHI 0x2C +#define XUSB_DEV_XHCI_CTRL 0x30 +#define XHCI_CTRL_RUN BIT(0) +#define XHCI_CTRL_LSE BIT(1) +#define XHCI_CTRL_IE BIT(4) +#define XHCI_CTRL_ENABLE BIT(31) +#define XUSB_DEV_XHCI_ST 0x34 +#define XHCI_ST_RC BIT(0) +#define XHCI_ST_IP BIT(4) +#define XUSB_DEV_XHCI_PORTSC 0x3C +#define XHCI_PORTSC_PR BIT(4) +#define XHCI_PORTSC_PLS_MASK (0xF << 5) +#define XHCI_PORTSC_PLS_U0 (0 << 5) +#define XHCI_PORTSC_PLS_U1 (1 << 5) +#define XHCI_PORTSC_PLS_U2 (2 << 5) +#define XHCI_PORTSC_PLS_U3 (3 << 5) +#define XHCI_PORTSC_PLS_DISABLED (4 << 5) +#define XHCI_PORTSC_PLS_RXDETECT (5 << 5) +#define XHCI_PORTSC_PLS_INACTIVE (6 << 5) +#define XHCI_PORTSC_PLS_POLLING (7 << 5) +#define XHCI_PORTSC_PLS_RECOVERY (8 << 5) +#define XHCI_PORTSC_PLS_HOTRESET (9 << 5) +#define XHCI_PORTSC_PLS_COMPLIANCE (10 << 5) +#define XHCI_PORTSC_PLS_LOOPBACK (11 << 5) +#define XHCI_PORTSC_PLS_RESUME (15 << 5) +#define XHCI_PORTSC_PS (0xF << 10) +#define XHCI_PORTSC_LWS BIT(16) +#define XHCI_PORTSC_CSC BIT(17) +#define XHCI_PORTSC_WRC BIT(19) +#define XHCI_PORTSC_PRC BIT(21) +#define XHCI_PORTSC_PLC BIT(22) +#define XHCI_PORTSC_CEC BIT(23) +#define XHCI_PORTSC_WPR BIT(30) +#define XUSB_DEV_XHCI_ECPLO 0x40 +#define XUSB_DEV_XHCI_ECPHI 0x44 +#define XUSB_DEV_XHCI_EP_HALT 0x50 +#define XHCI_EP_HALT_DCI BIT(0) +#define XUSB_DEV_XHCI_EP_PAUSE 0x54 +#define XUSB_DEV_XHCI_EP_RELOAD 0x58 +#define XUSB_DEV_XHCI_EP_STCHG 0x5C +#define XUSB_DEV_XHCI_PORTHALT 0x6C +#define XHCI_PORTHALT_HALT_LTSSM BIT(0) +#define XHCI_PORTHALT_STCHG_REQ BIT(20) +#define XUSB_DEV_XHCI_CFG_DEV_FE 0x85C +#define XHCI_CFG_DEV_FE_PORTREGSEL_MASK (3 << 0) +#define XHCI_CFG_DEV_FE_PORTREGSEL_SS (1 << 0) +#define XHCI_CFG_DEV_FE_PORTREGSEL_HSFS (2 << 0) + +/* XUSB DEV PCI registers */ +#define XUSB_CFG_1 0x4 +#define CFG_1_IO_SPACE BIT(0) +#define CFG_1_MEMORY_SPACE BIT(1) +#define CFG_1_BUS_MASTER BIT(2) +#define XUSB_CFG_4 0x10 +#define CFG_4_ADDRESS_TYPE_32_BIT (0 << 1) +#define CFG_4_ADDRESS_TYPE_64_BIT (2 << 1) + +/* XUSB DEV Device registers */ +#define XUSB_DEV_CONFIGURATION 0x180 +#define DEV_CONFIGURATION_EN_FPCI BIT(0) +#define XUSB_DEV_INTR_MASK 0x188 +#define DEV_INTR_MASK_IP_INT_MASK BIT(16) + +/* XUSB Pad Control registers */ +#define XUSB_PADCTL_USB2_PAD_MUX 0x4 +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_USB2 (0 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB (1 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK (3 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_USB2 (0 << 18) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB (1 << 18) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK (3 << 18) +#define XUSB_PADCTL_USB2_PORT_CAP 0x8 +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_DIS (0 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_HOST (1 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV (2 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_OTG (3 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK (3 << 0) +#define XUSB_PADCTL_SS_PORT_MAP 0x14 +#define PADCTL_SS_PORT_MAP_PORT0_MASK (0xF << 0) +#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20 +#define XUSB_PADCTL_ELPG_PROGRAM_1 0x24 +#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0 0x80 +#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1 0x84 +#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_0 0x88 +#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_1 0x8C +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_0 0x284 +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_1 0x288 +#define XUSB_PADCTL_USB2_VBUS_ID 0xC60 +#define PADCTL_USB2_VBUS_ID_VBUS_OVR_EN (1 << 12) +#define PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK (3 << 12) +#define PADCTL_USB2_VBUS_ID_VBUS_ON BIT(14) +#define PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN (1 << 16) +#define PADCTL_USB2_VBUS_ID_SRC_MASK (3 << 16) +#define PADCTL_USB2_VBUS_ID_OVR_GND (0 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_C (1 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_B (2 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_A (4 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_FLOAT (8 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_MASK (0xF << 18) + #endif diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c index 712629a..8cf37c3 100644 --- a/bdk/usb/usbd.c +++ b/bdk/usb/usbd.c @@ -1,7 +1,7 @@ /* - * USB Device driver for Tegra X1 + * Enhanced USB Device (EDCI) 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 * under the terms and conditions of the GNU General Public License, @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -42,20 +42,6 @@ typedef enum USB_HW_EP1 = 1 } usb_hw_ep_t; -typedef enum -{ - USB_EP_ADDR_CTRL_OUT = 0x00, - USB_EP_ADDR_CTRL_IN = 0x80, - USB_EP_ADDR_BULK_OUT = 0x01, - USB_EP_ADDR_BULK_IN = 0x81, -} usb_ep_addr_t; - -typedef enum -{ - USB_EP_CFG_RESET = 0, - USB_EP_CFG_STALL = 1 -} usb_ep_cfg_t; - typedef enum { USB_EP_STATUS_IDLE = 0, @@ -67,72 +53,12 @@ typedef enum } usb_ep_status_t; typedef enum { - USB_SETUP_RECIPIENT_DEVICE = 0, - USB_SETUP_RECIPIENT_INTERFACE = 1, - USB_SETUP_RECIPIENT_ENDPOINT = 2, - USB_SETUP_RECIPIENT_OTHER = 3, - - USB_SETUP_TYPE_STANDARD = 0x00, - USB_SETUP_TYPE_CLASS = 0x20, - USB_SETUP_TYPE_VENDOR = 0x40, - USB_SETUP_TYPE_RESERVED = 0x60, - - USB_SETUP_HOST_TO_DEVICE = 0x00, - USB_SETUP_DEVICE_TO_HOST = 0x80, -} usb_setup_req_type_t; - -typedef enum { - USB_REQUEST_GET_STATUS = 0, - USB_REQUEST_CLEAR_FEATURE = 1, - USB_REQUEST_SET_FEATURE = 3, - USB_REQUEST_SET_ADDRESS = 5, - USB_REQUEST_GET_DESCRIPTOR = 6, - USB_REQUEST_SET_DESCRIPTOR = 7, - USB_REQUEST_GET_CONFIGURATION = 8, - USB_REQUEST_SET_CONFIGURATION = 9, - USB_REQUEST_GET_INTERFACE = 10, - USB_REQUEST_SET_INTERFACE = 11, - USB_REQUEST_SYNCH_FRAME = 12, - - USB_REQUEST_GET_MS_DESCRIPTOR = 0x99, - - USB_REQUEST_BULK_GET_MAX_LUN = 0xFE, - USB_REQUEST_BULK_RESET = 0xFF -} usb_standard_req_t; - -typedef enum { - USB_FEATURE_ENDPOINT_HALT = 0, - USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, - USB_FEATURE_TEST_MODE = 2, -} usb_get_status_req_t; - -typedef enum { - USB_STATUS_EP_OK = 0, - USB_STATUS_EP_HALTED = 1, - - USB_STATUS_DEV_SELF_POWERED = 1, - USB_STATUS_DEV_REMOTE_WAKE = 2, -} usb_set_clear_feature_req_t; - -typedef enum { - USB_XFER_DIR_OUT = 0, - USB_XFER_DIR_IN = 1, -} usb_xfer_dir_t; - -typedef enum { - USB_SPEED_LOW = 0, - USB_SPEED_FULL = 1, - USB_SPEED_HIGH = 2, - USB_SPEED_SUPER = 3, + USB_LOW_SPEED = 0, + USB_FULL_SPEED = 1, + USB_HIGH_SPEED = 2, + USB_SUPER_SPEED = 3, } usb_speed_t; -typedef enum { - USB_XFER_TYPE_CONTROL = 0, - USB_XFER_TYPE_ISOCHRONOUS = 1, - USB_XFER_TYPE_BULK = 2, - USB_XFER_TYPE_INTERRUPT = 3, -} usb_xfer_type_t; - typedef struct _dTD_t { vu32 next_dTD; @@ -161,45 +87,32 @@ typedef struct _usbd_t int ep_bytes_requested[4]; } usbd_t; -typedef struct _usb_ctrl_setup_t -{ - u8 bmRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; -} usb_ctrl_setup_t; - typedef struct _usbd_controller_t { u32 port_speed; t210_usb2d_t *regs; usb_ctrl_setup_t control_setup; usb_desc_t *desc; - usb_gadget_type type; - u8 configuration_set; - u8 usb_phy_ready; - u8 configuration; - u8 interface; + usb_gadget_type gadget; + u8 config_num; + u8 interface_num; u8 max_lun; - u8 max_lun_set; - u8 bulk_reset_req; - u8 hid_report_sent; - bool charger_detect; + bool usb_phy_ready; + bool configuration_set; + bool max_lun_set; + bool bulk_reset_req; + bool hid_report_sent; + u32 charger_detect; } usbd_controller_t; -u8 usb_serial_string_descriptor[26] = -{ - 26, 0x03, - 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, - '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 -}; +extern u8 hid_report_descriptor_jc[]; +extern u8 hid_report_descriptor_touch[]; +extern u32 hid_report_descriptor_jc_size; +extern u32 hid_report_descriptor_touch_size; -u8 usb_lang_id_string_descriptor[] = -{ - 4, 3, - 0x09, 0x04 -}; +extern usb_desc_t usb_gadget_hid_jc_descriptors; +extern usb_desc_t usb_gadget_hid_touch_descriptors; +extern usb_desc_t usb_gadget_ums_descriptors; usbd_t *usbdaemon; @@ -212,7 +125,7 @@ u8 *usb_ep0_ctrl_buf = (u8 *)USB_EP_CONTROL_BUF_ADDR; static int _usbd_reset_usb_otg_phy_device_mode() { - usbd_otg->usb_phy_ready = 0; + usbd_otg->usb_phy_ready = false; // Clear UTMIP reset. USB(USB1_IF_USB_SUSP_CTRL) &= ~SUSP_CTRL_UTMIP_RESET; @@ -223,10 +136,10 @@ static int _usbd_reset_usb_otg_phy_device_mode() { retries--; if (!retries) - return 1; + return USB_ERROR_INIT; usleep(1); } - usbd_otg->usb_phy_ready = 1; + usbd_otg->usb_phy_ready = true; // Clear all device addresses, enabled setup requests and transmit events. usbd_otg->regs->periodiclistbase = 0; @@ -248,7 +161,7 @@ static int _usbd_reset_usb_otg_phy_device_mode() { retries--; if (!retries) - return 2; + return USB_ERROR_INIT; usleep(1); } @@ -258,7 +171,7 @@ static int _usbd_reset_usb_otg_phy_device_mode() { retries--; if (!retries) - return 3; + return USB_ERROR_INIT; usleep(1); } @@ -271,7 +184,7 @@ static int _usbd_reset_usb_otg_phy_device_mode() { retries--; if (!retries) - return 4; + return USB_ERROR_INIT; usleep(1); } @@ -296,7 +209,7 @@ static int _usbd_reset_usb_otg_phy_device_mode() // Set all interrupts to immediate. usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_ITC_MASK; - return 0; + return USB_RES_OK; } static void _usb_charger_detect() @@ -312,7 +225,7 @@ static void _usb_charger_detect() gpio_config(GPIO_PORT_V, GPIO_PIN_3, GPIO_MODE_GPIO); // Configure charger pin. - PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) &= + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) &= ~(PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); gpio_config(GPIO_PORT_CC, GPIO_PIN_5, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); @@ -329,45 +242,29 @@ static void _usb_charger_detect() } } -int usb_device_init() +static void _usb_init_phy() { - if (usb_init_done) - return 0; - - // Configure PLLU. - CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) = CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) | 0x20000000; // Disable reference clock. - u32 pllu_cfg = (((((CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) >> 8 << 8) | 2) & 0xFFFF00FF) | ((0x19 << 8) & 0xFFFF)) & 0xFFE0FFFF) | (1<< 16) | 0x1000000; - CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; - CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | 0x40000000; // Enable. - - // Wait for PLL to stabilize. - u32 timeout = (u32)TMR(TIMERUS_CNTR_1US) + 1300; - while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & (1 << 27))) // PLL_LOCK. - if ((u32)TMR(TIMERUS_CNTR_1US) > timeout) - break; - usleep(10); - - // Enable PLLU USB/HSIC/ICUSB/48M. - CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) | 0x2600000 | 0x800000; + // Configure and enable PLLU. + clock_enable_pllu(); // Enable USBD clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = (1 << 22); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_USBD); usleep(2); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = (1 << 22); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); usleep(2); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = (1 << 22); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_USBD); usleep(2); // Clear XUSB_PADCTL reset - CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = (1 << 14); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL); // Enable USB PHY and reset for programming. u32 usb_susp_ctrl = USB(USB1_IF_USB_SUSP_CTRL); USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_RESET; USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_PHY_ENB | SUSP_CTRL_UTMIP_RESET; - // Disable UTMIPLL IDDQ. - CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) &= 0xFFFFFFFD; + // Enable IDDQ control by software and disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1; usleep(10); // Disable crystal clock. @@ -378,18 +275,8 @@ int usb_device_init() USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x1000; USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x800; - // Set UTMIPLL dividers and enable it. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | 0x190000 | 0x100; - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | 0x600000; // Set delay count for 38.4Mhz osc crystal. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = ((CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) & 0x7FFF000) | 0x8000 | 0x177) & 0xFFFFAFFF; - - // Wait for UTMIPLL to stabilize. - u32 retries = 10; // Wait 20us - while (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0x80000000) && retries) - { - usleep(1); - retries--; - } + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + clock_enable_utmipll(); // Configure UTMIP Transceiver Cells. u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); @@ -418,8 +305,9 @@ int usb_device_init() // Enable crystal clock. CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= 0x40000000; - // Enable USB2 tracking. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= 0x40000; + + // Enable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_USB2_TRK); CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFC03F07) | 0x78000 | 0x50; // Set delays. @@ -441,8 +329,8 @@ int usb_device_init() // TRK cycle done. Force PDTRK input into power down. USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; - // Disable USB2_TRK clock and configure UTMIP misc. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) &= 0xFFFBFFFF; + // Disable USB2 tracking clock and configure UTMIP misc. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK); CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFEA) | 0x2000000 | 0x28 | 2; usleep(1); @@ -450,7 +338,7 @@ int usb_device_init() usleep(1); // Clear power downs on UTMIP ID and VBUS wake up, PD, PD2, PDZI, PDCHRP, PDDR. - PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up. + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up. usleep(1); USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFFBFFF; // UTMIP_FORCE_PD_POWERDOWN. usleep(1); @@ -462,13 +350,22 @@ int usb_device_init() usleep(1); USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFEF; // UTMIP_FORCE_PDDR_POWERDOWN. usleep(1); +} + +int usb_device_init() +{ + if (usb_init_done) + return USB_RES_OK; + + // Initialize USB2 controller PHY. + _usb_init_phy(); // AHB USB performance cfg. - AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_ENB_FAST_REARBITRATE; - AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_USB_IMMEDIATE; - AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) |= ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB; AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = - MEM_PREFETCH_ENABLE | (MEM_PREFETCH_AHB_MST_USB << 26) | (12 << 21) | 0x1000; // addr boundary 64KB + MEM_PREFETCH_ENABLE | MEM_PREFETCH_USB_MST_ID | MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles. // Set software and hardware context storage and clear it. usbdaemon = (usbd_t *)USBD_ADDR; // Depends on USB_TD_BUFFER_PAGE_SIZE aligned address. @@ -477,18 +374,18 @@ int usb_device_init() memset(usbdaemon, 0, sizeof(usbd_t)); usbd_otg->regs = (t210_usb2d_t *)USB_OTG_BASE; - usbd_otg->usb_phy_ready = 0; + usbd_otg->usb_phy_ready = false; // Initialize USB PHY on the USB_OTG Controller (#1) in Device mode. - int result = _usbd_reset_usb_otg_phy_device_mode(); - usbd_otg->configuration_set = 0; + int res = _usbd_reset_usb_otg_phy_device_mode(); + usbd_otg->configuration_set = false; _usb_charger_detect(); - if (!result) + if (!res) usb_init_done = true; - return result; + return res; } static void _usb_device_power_down() @@ -499,10 +396,10 @@ static void _usb_device_power_down() // A reset or clear of the PHCD suspend bit must happen. // Power down OTG and Bias circuits. - USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 11) | (1 << 10); // UTMIP_OTGPD, UTMIP_BIASPD. + USB(USB1_UTMIP_BIAS_CFG0) |= BIT(11) | BIT(10); // UTMIP_OTGPD, UTMIP_BIASPD. // Power down ID detectors. - USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 23) | (1 << 22); //UTMIP_IDPD_SEL, UTMIP_IDPD_VAL. + USB(USB1_UTMIP_BIAS_CFG0) |= BIT(23) | BIT(22); // UTMIP_IDPD_SEL, UTMIP_IDPD_VAL. if (usbd_otg->charger_detect) { @@ -512,46 +409,44 @@ static void _usb_device_power_down() // Power down the UTMIP transceivers. // UTMIP_FORCE_PDZI_POWERDOWN, UTMIP_FORCE_PD2_POWERDOWN, UTMIP_FORCE_PD_POWERDOWN. - USB(USB1_UTMIP_XCVR_CFG0) |= (1 << 18) | (1 << 16) |(1 << 14); + USB(USB1_UTMIP_XCVR_CFG0) |= BIT(18) | BIT(16) |BIT(14); // UTMIP_FORCE_PDDR_POWERDOWN, UTMIP_FORCE_PDCHRP_POWERDOWN, UTMIP_FORCE_PDDISC_POWERDOWN. - USB(USB1_UTMIP_XCVR_CFG1) |= (1 << 4) | (1 << 2) | (1 << 0); + USB(USB1_UTMIP_XCVR_CFG1) |= BIT(4) | BIT(2) | BIT(0); // Keep UTMIP in reset. USB(USB1_IF_USB_SUSP_CTRL) |= SUSP_CTRL_UTMIP_RESET; // Power down PD trunk. - USB(USB1_UTMIP_BIAS_CFG1) |= (1 << 0); //UTMIP_FORCE_PDTRK_POWERDOWN. + USB(USB1_UTMIP_BIAS_CFG1) |= BIT(0); //UTMIP_FORCE_PDTRK_POWERDOWN. // Force UTMIP_PLL power down. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 14); // UTMIP_FORCE_PLL_ENABLE_POWERDOWN. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 12); // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= (1 << 4) | (1 << 0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. - CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 16); // UTMIP_FORCE_PLLU_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(14); // UTMIP_FORCE_PLL_ENABLE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(12); // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(16); // UTMIP_FORCE_PLLU_POWERDOWN. // Disable crystal clock. USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; - // Enable UTMIPLL IDDQ. - CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 2; + // Force enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3; // Set XUSB_PADCTL reset - CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = (1 << 14); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); // Disable USBD clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = (1 << 22); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD); - // Completely disable PLLU. - CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M. - CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x40000000; // Disable PLLU. - CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~0x20000000; // Enable reference clock. + // Disable PLLU. + clock_disable_pllu(); usb_init_done = false; } -static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall) +static void _usbd_stall_reset_ep1(usb_dir_t direction, usb_ep_cfg_t stall) { stall &= 1; - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) { usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16); if (!stall) @@ -565,42 +460,17 @@ static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall) } } -void usbd_end(bool reset_ep, bool only_controller) -{ - if (reset_ep) - { - usbd_flush_endpoint(USB_EP_ALL); - _usbd_stall_reset_ep1(0, USB_EP_CFG_RESET); // EP1 Bulk IN. - _usbd_stall_reset_ep1(1, USB_EP_CFG_RESET); // EP1 Bulk OUT. - //TODO: what about EP0 simultaneous in/out reset. - - usbd_otg->configuration = 0; - usbd_otg->interface = 0; - usbd_otg->configuration_set = 0; - usbd_otg->max_lun_set = 0; - } - - // Stop device controller. - usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; - - // Enable PHY auto low power suspend. - usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS; - - if (!only_controller) - _usb_device_power_down(); -} - void usb_device_stall_ep1_bulk_out() { - _usbd_stall_reset_ep1(USB_XFER_DIR_OUT, USB_EP_CFG_STALL); + _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_STALL); } void usb_device_stall_ep1_bulk_in() { - _usbd_stall_reset_ep1(USB_XFER_DIR_IN, USB_EP_CFG_STALL); + _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_STALL); } -int usbd_get_max_pkt_length(int endpoint) +static int _usbd_get_max_pkt_length(int endpoint) { switch (endpoint) { @@ -609,7 +479,7 @@ int usbd_get_max_pkt_length(int endpoint) return 64; case USB_EP_BULK_OUT: case USB_EP_BULK_IN: - if (usbd_otg->port_speed == 2) + if (usbd_otg->port_speed == USB_HIGH_SPEED) return 512; else return 64; @@ -621,7 +491,7 @@ int usbd_get_max_pkt_length(int endpoint) static void _usbd_initialize_ep_ctrl(u32 endpoint) { usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); @@ -630,14 +500,14 @@ static void _usbd_initialize_ep_ctrl(u32 endpoint) usbdaemon->qhs[endpoint].next_dTD_ptr = 1; // TERMINATE_SET - u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + u32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16; - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) { u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK; if (actual_ep) - endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK; + endpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK; else endpoint_type |= USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL; @@ -655,7 +525,7 @@ static void _usbd_initialize_ep_ctrl(u32 endpoint) u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_RX_EP_TYPE_MASK; if (actual_ep) { - endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK; + endpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK; } else endpoint_type |= USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL; @@ -691,11 +561,11 @@ static int _usbd_initialize_ep0() { retries--; if (!retries) - return 3; + return USB_ERROR_TIMEOUT; usleep(1); } - return 0; + return USB_RES_OK; } // static void _disable_usb_wdt4() @@ -713,13 +583,13 @@ int usbd_flush_endpoint(u32 endpoint) { usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; u32 reg_mask = endpoint; // Flash all endpoints or 1. if (endpoint != USB_EP_ALL) { - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; else reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; @@ -731,7 +601,7 @@ int usbd_flush_endpoint(u32 endpoint) { retries--; if (!retries) - return 3; + return USB_ERROR_TIMEOUT; usleep(1); } @@ -741,7 +611,7 @@ int usbd_flush_endpoint(u32 endpoint) { retries--; if (!retries) - return 3; + return USB_ERROR_TIMEOUT; usleep(1); } @@ -751,18 +621,42 @@ int usbd_flush_endpoint(u32 endpoint) { retries--; if (!retries) - return 3; + return USB_ERROR_TIMEOUT; usleep(1); } - return 0; + return USB_RES_OK; +} + +void usbd_end(bool reset_ep, bool only_controller) +{ + if (reset_ep) + { + usbd_flush_endpoint(USB_EP_ALL); + _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_RESET); // EP1 Bulk OUT. + _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_RESET); // EP1 Bulk IN. + + usbd_otg->config_num = 0; + usbd_otg->interface_num = 0; + usbd_otg->configuration_set = false; + usbd_otg->max_lun_set = false; + } + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Enable PHY auto low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS; + + if (!only_controller) + _usb_device_power_down(); } static void _usbd_mark_ep_complete(u32 endpoint) { u32 complete_bit; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; usbd_flush_endpoint(endpoint); memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4); @@ -770,7 +664,7 @@ static void _usbd_mark_ep_complete(u32 endpoint) usbdaemon->ep_configured[endpoint] = 0; usbdaemon->ep_bytes_requested[endpoint] = 0; - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; else complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; @@ -784,9 +678,9 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) u32 reg_val; u32 reg_mask; u32 actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; else reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; @@ -797,7 +691,7 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) reg_val = usbd_otg->regs->endptctrl[0]; // Check stalled status. - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL; else status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL; @@ -806,7 +700,7 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) return USB_EP_STATUS_STALLED; // Check enabled status. - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE; else status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE; @@ -837,7 +731,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) u32 prime_bit; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; u32 length_left = len; u32 dtd_ep_idx = endpoint * 4; @@ -846,7 +740,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) if (endpoint == USB_EP_CTRL_OUT) usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; - u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + u32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; usbdaemon->qhs[endpoint].ep_capabilities |= (max_packet_len << 16) | USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS; usbdaemon->qhs[endpoint].next_dTD_ptr = 0; // Clear terminate bit. //usbdaemon->qhs[endpoint].ep_capabilities |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; @@ -890,7 +784,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE; AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE; - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) { prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); @@ -901,7 +795,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) // Prime endpoint. usbd_otg->regs->endptprime |= prime_bit; // USB2_CONTROLLER_USB2D_ENDPTPRIME. - int res = 0; + int res = USB_RES_OK; usb_ep_status_t ep_status; if (sync) { @@ -915,25 +809,25 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) if (ep_status != USB_EP_STATUS_ACTIVE) { if (ep_status == USB_EP_STATUS_DISABLED) - res = 28; + res = USB2_ERROR_XFER_EP_DISABLED; goto out; } retries--; usleep(1); } - res = 3; + res = USB_ERROR_TIMEOUT; } else if (ep_status == USB_EP_STATUS_DISABLED) - res = 28; + res = USB2_ERROR_XFER_EP_DISABLED; out: if (res) _usbd_mark_ep_complete(endpoint); else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE) - res = 26; - } + res = USB_ERROR_XFER_ERROR; - if (direction == USB_XFER_DIR_OUT) - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + if (direction == USB_DIR_OUT) + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + } return res; } @@ -951,40 +845,42 @@ static void _usbd_set_ep0_stall() USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL; } -void usbd_set_ep_stall(u32 endpoint, int ep_stall) +int usbd_set_ep_stall(u32 endpoint, int ep_stall) { usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; - usb_xfer_dir_t direction = endpoint & 1; + usb_dir_t direction = endpoint & 1; if (ep_stall) { - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN. else usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT. } else { - if (direction == USB_XFER_DIR_IN) + if (direction == USB_DIR_IN) usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN. else usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT. } + + return USB_RES_OK; } -static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, int *ep_stall) +static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, bool *ep_stall) { u8 _bRequest = usbd_otg->control_setup.bRequest; u16 _wIndex = usbd_otg->control_setup.wIndex; u16 _wValue = usbd_otg->control_setup.wValue; u16 _wLength = usbd_otg->control_setup.wLength; - bool valid_interface = _wIndex == usbd_otg->interface; - bool valid_len = _bRequest == USB_REQUEST_BULK_GET_MAX_LUN ? 1 : 0; + bool valid_interface = _wIndex == usbd_otg->interface_num; + bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0; if (!valid_interface || _wValue != 0 || _wLength != valid_len) { - *ep_stall = 1; + *ep_stall = true; return; } @@ -992,20 +888,21 @@ static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, { case USB_REQUEST_BULK_RESET: _usbd_ep_ack(USB_EP_CTRL_IN); - usbd_otg->bulk_reset_req = 1; + usbd_otg->bulk_reset_req = true; break; // DELAYED_STATUS; case USB_REQUEST_BULK_GET_MAX_LUN: - *transmit_data = 1; + *transmit_data = true; + *size = 1; descriptor[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported. - usbd_otg->max_lun_set = 1; + usbd_otg->max_lun_set = true; break; default: - *ep_stall = 1; + *ep_stall = true; break; } } -static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, int *size, int *ep_stall) +static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, int *size, bool *ep_stall) { u8 descriptor_type = usbd_otg->control_setup.wValue >> 8; u8 descriptor_subtype = usbd_otg->control_setup.wValue & 0xFF; @@ -1023,13 +920,13 @@ static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, */ *descriptor = usbd_otg->desc->dev; *size = usbd_otg->desc->dev->bLength; - *transmit_data = 1; + *transmit_data = true; return; } case USB_DESCRIPTOR_CONFIGURATION: - if (usbd_otg->type == USB_GADGET_UMS) + if (usbd_otg->gadget == USB_GADGET_UMS) { - if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + if (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes. { usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; @@ -1043,20 +940,24 @@ static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, else { usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_otg->desc->cfg; - if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + if (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes. { tmp->endpoint[0].wMaxPacketSize = 0x200; tmp->endpoint[1].wMaxPacketSize = 0x200; + tmp->endpoint[0].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. } else // Full speed. 64 bytes. { tmp->endpoint[0].wMaxPacketSize = 0x40; tmp->endpoint[1].wMaxPacketSize = 0x40; + tmp->endpoint[0].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. } } *descriptor = usbd_otg->desc->cfg; *size = usbd_otg->desc->cfg->config.wTotalLength; - *transmit_data = 1; + *transmit_data = true; return; case USB_DESCRIPTOR_STRING: switch (descriptor_subtype) @@ -1070,31 +971,32 @@ static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, *size = usbd_otg->desc->product[0]; break; case 3: - *descriptor = usb_serial_string_descriptor; - *size = usb_serial_string_descriptor[0]; + *descriptor = usbd_otg->desc->serial; + *size = usbd_otg->desc->serial[0]; break; case 0xEE: *descriptor = usbd_otg->desc->ms_os; *size = usbd_otg->desc->ms_os->bLength; break; default: - *descriptor = usb_lang_id_string_descriptor; + *descriptor = usbd_otg->desc->lang_id; *size = 4; break; } - *transmit_data = 1; + *transmit_data = true; return; case USB_DESCRIPTOR_DEVICE_QUALIFIER: if (!usbd_otg->desc->dev_qual) goto exit; + usbd_otg->desc->dev_qual->bNumOtherConfigs = 1; *descriptor = usbd_otg->desc->dev_qual; *size = usbd_otg->desc->dev_qual->bLength; - *transmit_data = 1; + *transmit_data = true; return; case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: if (!usbd_otg->desc->cfg_other) goto exit; - if (usbd_otg->port_speed == 2) + if (usbd_otg->port_speed == USB_HIGH_SPEED) { usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; @@ -1108,62 +1010,61 @@ static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, usbd_otg->desc->cfg_other->config.bMaxPower = 500 / 2; *descriptor = usbd_otg->desc->cfg_other; *size = usbd_otg->desc->cfg_other->config.wTotalLength; - *transmit_data = 1; + *transmit_data = true; return; case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: *descriptor = usbd_otg->desc->dev_bot; *size = usbd_otg->desc->dev_bot->wTotalLength; - *transmit_data = 1; + *transmit_data = true; return; default: - *transmit_data = 0; - *ep_stall = 1; + *transmit_data = false; + *ep_stall = true; return; } exit: - *transmit_data = 0; - *ep_stall = 1; + *transmit_data = false; + *ep_stall = true; return; } -static int _usbd_handle_set_request(int *ep_stall) +static int _usbd_handle_set_request(bool *ep_stall) { - int ret = 0; + int res = USB_RES_OK; u8 bRequest = usbd_otg->control_setup.bRequest; if (bRequest == USB_REQUEST_SET_ADDRESS) { - ret = _usbd_ep_ack(USB_EP_CTRL_IN); + res = _usbd_ep_ack(USB_EP_CTRL_IN); // Set USB address for device mode. - if (!ret) + if (!res) usbd_otg->regs->periodiclistbase = (usbd_otg->regs->periodiclistbase & 0x1FFFFFF) | ((usbd_otg->control_setup.wValue & 0xFF) << 25); } else if (bRequest == USB_REQUEST_SET_CONFIGURATION) { - ret = _usbd_ep_ack(USB_EP_CTRL_IN); - if (!ret) + res = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!res) { - usbd_otg->configuration = usbd_otg->control_setup.wValue; + usbd_otg->config_num = usbd_otg->control_setup.wValue; _usbd_initialize_ep_ctrl(USB_EP_BULK_OUT); _usbd_initialize_ep_ctrl(USB_EP_BULK_IN); - usbd_otg->configuration_set = 1; + usbd_otg->configuration_set = true; } } else - *ep_stall = 1; + *ep_stall = true; - return ret; + return res; } static int _usbd_handle_ep0_control_transfer() { - int direction; + int res = USB_RES_OK; + bool ep_stall = false; + bool transmit_data = false; - int ret = 0; - bool transmit_data = 0; u8 *descriptor = (u8 *)USB_DESCRIPTOR_ADDR; int size = 0; - int ep_stall = 0; u8 _bmRequestType = usbd_otg->control_setup.bmRequestType; u8 _bRequest = usbd_otg->control_setup.bRequest; @@ -1175,23 +1076,24 @@ static int _usbd_handle_ep0_control_transfer() switch (_bmRequestType) { - case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): - ret = _usbd_handle_set_request(&ep_stall); + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + res = _usbd_handle_set_request(&ep_stall); break; - case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): - ret = _usbd_ep_ack(USB_EP_CTRL_IN); - if (!ret) - usbd_otg->interface = _wValue; + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + res = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!res) + usbd_otg->interface_num = _wValue; break; - case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): switch (_bRequest) { case USB_REQUEST_CLEAR_FEATURE: case USB_REQUEST_SET_FEATURE: if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) { + int direction; switch (_wIndex) // endpoint { case USB_EP_ADDR_CTRL_OUT: @@ -1216,94 +1118,101 @@ static int _usbd_handle_ep0_control_transfer() else _usbd_stall_reset_ep1(direction, USB_EP_CFG_STALL); - ret = _usbd_ep_ack(USB_EP_CTRL_IN); + res = _usbd_ep_ack(USB_EP_CTRL_IN); } else _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); break; default: - ep_stall = 1; + ep_stall = true; break; } break; - case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + memset(descriptor, 0, _wLength); _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); break; - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): switch (_bRequest) { case USB_REQUEST_GET_STATUS: descriptor[0] = USB_STATUS_DEV_SELF_POWERED; descriptor[1] = 0; // No support for remove wake up. - transmit_data = 1; + transmit_data = true; size = 2; break; case USB_REQUEST_GET_DESCRIPTOR: _usbd_handle_get_descriptor(&transmit_data, (void **)&descriptor, &size, &ep_stall); break; case USB_REQUEST_GET_CONFIGURATION: - descriptor = (u8 *)&usbd_otg->configuration; + descriptor = (u8 *)&usbd_otg->config_num; size = _wLength; - transmit_data = 1; + transmit_data = true; break; default: - ep_stall = 1; + ep_stall = true; break; } break; - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): if (_bRequest == USB_REQUEST_GET_INTERFACE) { - descriptor = (void *)&usbd_otg->interface; + memset(descriptor, 0, _wLength); + descriptor[0] = usbd_otg->interface_num; + size = _wLength; } else if (_bRequest == USB_REQUEST_GET_STATUS) { memset(descriptor, 0, _wLength); + size = _wLength; } - else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->type > USB_GADGET_UMS) + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->gadget > USB_GADGET_UMS) { - if (usbd_otg->type == USB_GADGET_HID_GAMEPAD) + if (usbd_otg->gadget == USB_GADGET_HID_GAMEPAD) { descriptor = (u8 *)&hid_report_descriptor_jc; - _wLength = sizeof(hid_report_descriptor_jc); + size = hid_report_descriptor_jc_size; } else // USB_GADGET_HID_TOUCHPAD { descriptor = (u8 *)&hid_report_descriptor_touch; - _wLength = sizeof(hid_report_descriptor_touch); + size = hid_report_descriptor_touch_size; } - usbd_otg->hid_report_sent = 1; + usbd_otg->hid_report_sent = true; } else { - ep_stall = 1; + ep_stall = true; break; } - size = _wLength; - transmit_data = 1; + if (_wLength < size) + size = _wLength; + transmit_data = true; break; - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): if (_bRequest == USB_REQUEST_GET_STATUS) { int ep_req; switch (_wIndex) { - case 0: - ep_req = 0; + case USB_EP_ADDR_CTRL_OUT: + ep_req = USB_EP_CTRL_OUT; break; - case 1: - ep_req = 2; + case USB_EP_ADDR_BULK_OUT: + ep_req = USB_EP_BULK_OUT; break; - case 0x80: - ep_req = 1; + case USB_EP_ADDR_CTRL_IN: + ep_req = USB_EP_CTRL_IN; break; - case 0x81: - ep_req = 3; + case USB_EP_ADDR_BULK_IN: + ep_req = USB_EP_BULK_IN; break; default: _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); @@ -1318,20 +1227,19 @@ static int _usbd_handle_ep0_control_transfer() else descriptor[0] = USB_STATUS_EP_OK; - transmit_data = 1; + transmit_data = true; } else _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); break; - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): memset(descriptor, 0, _wLength); - _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); - size = _wLength; break; - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR): - case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR): + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_INTERFACE): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE): if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) { switch (_wIndex) @@ -1339,24 +1247,24 @@ static int _usbd_handle_ep0_control_transfer() case USB_DESCRIPTOR_MS_COMPAT_ID: descriptor = (u8 *)usbd_otg->desc->ms_cid; size = usbd_otg->desc->ms_cid->dLength; - transmit_data = 1; + transmit_data = true; break; case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: descriptor = (u8 *)usbd_otg->desc->mx_ext; size = usbd_otg->desc->mx_ext->dLength; - transmit_data = 1; + transmit_data = true; break; default: - ep_stall = 1; + ep_stall = true; break; } } else - ep_stall = 1; + ep_stall = true; break; default: - ep_stall = 1; + ep_stall = true; break; } @@ -1367,16 +1275,16 @@ static int _usbd_handle_ep0_control_transfer() if (_wLength < size) size = _wLength; - ret = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, true); - if (!ret) - ret = _usbd_ep_ack(USB_EP_CTRL_OUT); + res = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, true); + if (!res) + res = _usbd_ep_ack(USB_EP_CTRL_OUT); } out: if (ep_stall) _usbd_set_ep0_stall(); - return ret; + return res; } static int _usbd_ep0_initialize() @@ -1394,8 +1302,8 @@ static int _usbd_ep0_initialize() if (enter) { - usbd_otg->configuration_set = 0; - usbd_otg->max_lun_set = 0; + usbd_otg->configuration_set = false; + usbd_otg->max_lun_set = false; // Timeout if cable or communication isn't started in 1.5 minutes. u32 timer = get_tmr_ms() + 90000; @@ -1432,19 +1340,19 @@ static int _usbd_ep0_initialize() break; } if (usbd_otg->configuration_set) - return 0; + return USB_RES_OK; if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) - return 2; + return USB_ERROR_USER_ABORT; } } - return 3; + return USB_ERROR_TIMEOUT; } -int usb_device_ep0_initialize(usb_gadget_type type) +int usb_device_enumerate(usb_gadget_type gadget) { - switch (type) + switch (gadget) { case USB_GADGET_UMS: usbd_otg->desc = &usb_gadget_ums_descriptors; @@ -1457,15 +1365,12 @@ int usb_device_ep0_initialize(usb_gadget_type type) break; } - usbd_otg->type = type; + usbd_otg->gadget = gadget; - int result = _usbd_ep0_initialize(); - if (result) - result = 8; - return result; + return _usbd_ep0_initialize(); } -int usbd_handle_ep0_pending_control_transfer() +int usbd_handle_ep0_ctrl_setup() { // Acknowledge setup request for EP0 and copy its configuration. u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; @@ -1477,49 +1382,51 @@ int usbd_handle_ep0_pending_control_transfer() memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE); } + // Only return error if bulk reset was requested. if (usbd_otg->bulk_reset_req) { - usbd_otg->bulk_reset_req = 0; - return 1; + usbd_otg->bulk_reset_req = false; + return USB_RES_BULK_RESET; } - return 0; + return USB_RES_OK; } -static usb_ep_status_t _usbd_get_ep1_status(usb_xfer_dir_t dir) +static usb_ep_status_t _usbd_get_ep1_status(usb_dir_t dir) { usb_ep_t ep; - if (dir == USB_XFER_DIR_OUT) + if (dir == USB_DIR_OUT) ep = USB_EP_BULK_OUT; else ep = USB_EP_BULK_IN; return _usbd_get_ep_status(ep); } -int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync) +int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) { + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; - int result = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync); + int res = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync); if (sync && bytes_read) - { - if (result) - *bytes_read = 0; - else - *bytes_read = len; - } + *bytes_read = res ? 0 : len; - return result; + return res; } -int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read) +int usb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) { + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + if (len > USB_EP_BULK_OUT_MAX_XFER) len = USB_EP_BULK_OUT_MAX_XFER; - int result; + int res; u32 bytes = 0; *bytes_read = 0; u8 *buf_curr = buf; @@ -1528,75 +1435,73 @@ int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read) { u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); - result = usb_device_read_ep1_out(buf_curr, len_ep, &bytes, true); - if (!result) - { - len -= len_ep; - buf_curr += len_ep; - *bytes_read = *bytes_read + bytes; - } - else - break; + res = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED); + if (res) + return res; + + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; } - return result; + return USB_RES_OK; } static int _usbd_get_ep1_out_bytes_read() { - if (_usbd_get_ep_status(2) != USB_EP_STATUS_IDLE) + if (_usbd_get_ep_status(USB_EP_BULK_OUT) != USB_EP_STATUS_IDLE) return 0; else - return (usbdaemon->ep_bytes_requested[2] - (usbdaemon->qhs[2].token >> 16)); + return (usbdaemon->ep_bytes_requested[USB_EP_BULK_OUT] - (usbdaemon->qhs[USB_EP_BULK_OUT].token >> 16)); } -int usb_device_ep1_out_reading_finish(u32 *pending_bytes) +int usb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) { usb_ep_status_t ep_status; do { - ep_status = _usbd_get_ep1_status(USB_XFER_DIR_OUT); + ep_status = _usbd_get_ep1_status(USB_DIR_OUT); if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) break; - usbd_handle_ep0_pending_control_transfer(); + usbd_handle_ep0_ctrl_setup(); } while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); *pending_bytes = _usbd_get_ep1_out_bytes_read(); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + if (ep_status == USB_EP_STATUS_IDLE) - return 0; + return USB_RES_OK; else if (ep_status == USB_EP_STATUS_DISABLED) - return 28; + return USB2_ERROR_XFER_EP_DISABLED; else - return 26; + return USB_ERROR_XFER_ERROR; } -int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync) +int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) { + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; - int result = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync); + int res = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync); if (sync && bytes_written) - { - if (result) - *bytes_written = 0; - else - *bytes_written = len; - } + *bytes_written = res ? 0 : len; - return result; + return res; } static int _usbd_get_ep1_in_bytes_written() { - if (_usbd_get_ep_status(3) != USB_EP_STATUS_IDLE) + if (_usbd_get_ep_status(USB_EP_BULK_IN) != USB_EP_STATUS_IDLE) return 0; else - return (usbdaemon->ep_bytes_requested[3] - (usbdaemon->qhs[3].token >> 16)); + return (usbdaemon->ep_bytes_requested[USB_EP_BULK_IN] - (usbdaemon->qhs[USB_EP_BULK_IN].token >> 16)); } int usb_device_ep1_in_writing_finish(u32 *pending_bytes) @@ -1604,37 +1509,38 @@ int usb_device_ep1_in_writing_finish(u32 *pending_bytes) usb_ep_status_t ep_status; do { - ep_status = _usbd_get_ep1_status(USB_XFER_DIR_IN); + ep_status = _usbd_get_ep1_status(USB_DIR_IN); if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) break; - usbd_handle_ep0_pending_control_transfer(); + usbd_handle_ep0_ctrl_setup(); } while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); *pending_bytes = _usbd_get_ep1_in_bytes_written(); if (ep_status == USB_EP_STATUS_IDLE) - return 0; + return USB_RES_OK; else if (ep_status == USB_EP_STATUS_DISABLED) - return 28; + return USB2_ERROR_XFER_EP_DISABLED; usb_device_stall_ep1_bulk_out(); - return 26; + return USB_ERROR_XFER_ERROR; } bool usb_device_get_suspended() { - u32 suspended = usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP; - return (suspended ? true : false); + bool suspended = (usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP) == USB2D_PORTSC1_SUSP; + return suspended; } -u32 usb_device_get_port_status() +bool usb_device_get_port_in_sleep() { - return (usbd_otg->regs->portsc1); + // Windows heuristic: Forces port into suspend, sleep and J-State. + return (usbd_otg->regs->portsc1) == 0x885; } -bool usb_device_get_max_lun(u8 max_lun) +int usb_device_class_send_max_lun(u8 max_lun) { // Timeout if get MAX_LUN request doesn't happen in 10s. u32 timer = get_tmr_ms() + 10000; @@ -1643,25 +1549,47 @@ bool usb_device_get_max_lun(u8 max_lun) while (!usbd_otg->max_lun_set) { - usbd_handle_ep0_pending_control_transfer(); + usbd_handle_ep0_ctrl_setup(); if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) - return true; + return USB_ERROR_USER_ABORT; } - return false; + return USB_RES_OK; } -bool usb_device_get_hid_report() +int usb_device_class_send_hid_report() { // Timeout if get GET_HID_REPORT request doesn't happen in 10s. u32 timer = get_tmr_ms() + 10000; + // Wait for request and transfer start. while (!usbd_otg->hid_report_sent) { - usbd_handle_ep0_pending_control_transfer(); + usbd_handle_ep0_ctrl_setup(); if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) - return true; + return USB_ERROR_USER_ABORT; } - return false; + return USB_RES_OK; } + +void usb_device_get_ops(usb_ops_t *ops) +{ + ops->usbd_flush_endpoint = usbd_flush_endpoint; + ops->usbd_set_ep_stall = usbd_set_ep_stall; + ops->usbd_handle_ep0_ctrl_setup = usbd_handle_ep0_ctrl_setup; + ops->usbd_end = usbd_end; + ops->usb_device_init = usb_device_init; + ops->usb_device_enumerate = usb_device_enumerate; + ops->usb_device_class_send_max_lun = usb_device_class_send_max_lun; + ops->usb_device_class_send_hid_report = usb_device_class_send_hid_report; + ops->usb_device_get_suspended = usb_device_get_suspended; + ops->usb_device_get_port_in_sleep = usb_device_get_port_in_sleep; + + ops->usb_device_ep1_out_read = usb_device_ep1_out_read; + ops->usb_device_ep1_out_read_big = usb_device_ep1_out_read_big; + ops->usb_device_ep1_out_reading_finish = usb_device_ep1_out_reading_finish; + ops->usb_device_ep1_in_write = usb_device_ep1_in_write; + ops->usb_device_ep1_in_writing_finish = usb_device_ep1_in_writing_finish; +} + diff --git a/bdk/usb/usbd.h b/bdk/usb/usbd.h index 82a73e2..6ba2a5a 100644 --- a/bdk/usb/usbd.h +++ b/bdk/usb/usbd.h @@ -1,5 +1,5 @@ /* - * USB Device driver for Tegra X1 + * Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1 * * Copyright (c) 2019 CTCaer * @@ -28,6 +28,155 @@ #define USB_EP_BUFFER_2_TD (USB_TD_BUFFER_MAX_SIZE * 2) #define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4) #define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) +#define USB_EP_BUFFER_ALIGN (USB_TD_BUFFER_PAGE_SIZE) + +#define USB_XFER_START false +#define USB_XFER_SYNCED true + +typedef enum _usb_hid_type +{ + USB_HID_GAMEPAD, + USB_HID_TOUCHPAD +} usb_hid_type; + +typedef enum _usb_gadget_type +{ + USB_GADGET_UMS = 0, + USB_GADGET_HID_GAMEPAD = 1, + USB_GADGET_HID_TOUCHPAD = 2, +} usb_gadget_type; + +typedef enum { + USB_DIR_OUT = 0, + USB_DIR_IN = 1, +} usb_dir_t; + +typedef enum +{ + XUSB_EP_CTRL_IN = 0, // EP0. + XUSB_EP_CTRL_OUT = 1, // EP0. + + USB_EP_CTRL_OUT = 0, // EP0. + USB_EP_CTRL_IN = 1, // EP0. + + USB_EP_BULK_OUT = 2, // EP1. + USB_EP_BULK_IN = 3, // EP1. + USB_EP_ALL = 0xFFFFFFFF +} usb_ep_t; + +typedef enum +{ + USB_EP_ADDR_CTRL_OUT = 0x00, + USB_EP_ADDR_CTRL_IN = 0x80, + USB_EP_ADDR_BULK_OUT = 0x01, + USB_EP_ADDR_BULK_IN = 0x81, +} usb_ep_addr_t; + +typedef enum +{ + USB_EP_CFG_CLEAR = 0, + USB_EP_CFG_RESET = 0, + USB_EP_CFG_STALL = 1 +} usb_ep_cfg_t; + +typedef enum { + USB_STATUS_EP_OK = 0, + USB_STATUS_EP_HALTED = 1, + + USB_STATUS_DEV_SELF_POWERED = 1, + USB_STATUS_DEV_REMOTE_WAKE = 2, +} usb_set_clear_feature_req_t; + +typedef enum { + USB_SETUP_RECIPIENT_DEVICE = 0, + USB_SETUP_RECIPIENT_INTERFACE = 1, + USB_SETUP_RECIPIENT_ENDPOINT = 2, + USB_SETUP_RECIPIENT_OTHER = 3, + + USB_SETUP_TYPE_STANDARD = 0x00, + USB_SETUP_TYPE_CLASS = 0x20, + USB_SETUP_TYPE_VENDOR = 0x40, + USB_SETUP_TYPE_RESERVED = 0x60, + + USB_SETUP_HOST_TO_DEVICE = 0x00, + USB_SETUP_DEVICE_TO_HOST = 0x80, +} usb_setup_req_type_t; + +typedef enum { + USB_REQUEST_GET_STATUS = 0, + USB_REQUEST_CLEAR_FEATURE = 1, + USB_REQUEST_SET_FEATURE = 3, + USB_REQUEST_SET_ADDRESS = 5, + USB_REQUEST_GET_DESCRIPTOR = 6, + USB_REQUEST_SET_DESCRIPTOR = 7, + USB_REQUEST_GET_CONFIGURATION = 8, + USB_REQUEST_SET_CONFIGURATION = 9, + USB_REQUEST_GET_INTERFACE = 10, + USB_REQUEST_SET_INTERFACE = 11, + USB_REQUEST_SYNCH_FRAME = 12, + USB_REQUEST_SET_SEL = 13, + + USB_REQUEST_GET_MS_DESCRIPTOR = 0x99, + + USB_REQUEST_BULK_GET_MAX_LUN = 0xFE, + USB_REQUEST_BULK_RESET = 0xFF +} usb_standard_req_t; + +typedef enum { + USB_FEATURE_ENDPOINT_HALT = 0, + USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +} usb_get_status_req_t; + +typedef enum _usb_error_t +{ + USB_RES_OK = 0, + USB_RES_BULK_RESET = 1, + + USB_ERROR_USER_ABORT = 2, + USB_ERROR_TIMEOUT = 3, + USB_ERROR_INIT = 4, + USB_ERROR_XFER_ERROR = 5, + + USB2_ERROR_XFER_EP_DISABLED = 28, + USB2_ERROR_XFER_NOT_ALIGNED = 29, + + XUSB_ERROR_INVALID_EP = USB_ERROR_XFER_ERROR, // From 2. + XUSB_ERROR_XFER_BULK_IN_RESIDUE = 7, + XUSB_ERROR_INVALID_CYCLE = USB2_ERROR_XFER_EP_DISABLED, // From 8. + XUSB_ERROR_SEQ_NUM = 51, + XUSB_ERROR_XFER_DIR = 52, + XUSB_ERROR_PORT_CFG = 54 +} usb_error_t; + +typedef struct _usb_ctrl_setup_t +{ + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} usb_ctrl_setup_t; + +typedef struct _usb_ops_t +{ + int (*usbd_flush_endpoint)(u32); + int (*usbd_set_ep_stall)(u32, int); + int (*usbd_handle_ep0_ctrl_setup)(); + void (*usbd_end)(bool, bool); + int (*usb_device_init)(); + int (*usb_device_enumerate)(usb_gadget_type gadget); + int (*usb_device_class_send_max_lun)(u8); + int (*usb_device_class_send_hid_report)(); + + int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, bool); + int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *); + int (*usb_device_ep1_out_reading_finish)(u32 *, int); + int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, bool); + int (*usb_device_ep1_in_writing_finish)(u32 *); + bool (*usb_device_get_suspended)(); + bool (*usb_device_get_port_in_sleep)(); +} usb_ops_t; typedef struct _usb_ctxt_t { @@ -41,46 +190,10 @@ typedef struct _usb_ctxt_t void (*set_text)(void *, const char *); } usb_ctxt_t; -typedef enum _usb_hid_type -{ - USB_HID_GAMEPAD, - USB_HID_TOUCHPAD -} usb_hid_type; - -typedef enum _usb_gadget_type -{ - USB_GADGET_UMS, - USB_GADGET_HID_GAMEPAD, - USB_GADGET_HID_TOUCHPAD -} usb_gadget_type; - -typedef enum -{ - USB_EP_CTRL_OUT = 0, // EP0. - USB_EP_CTRL_IN = 1, // EP0. - USB_EP_BULK_OUT = 2, // EP1. - USB_EP_BULK_IN = 3, // EP1. - USB_EP_ALL = 0xFFFFFFFF -} usb_ep_t; - -int usbd_flush_endpoint(u32 ep); -void usbd_set_ep_stall(u32 endpoint, int ep_stall); -int usbd_get_max_pkt_length(int endpoint); -int usbd_handle_ep0_pending_control_transfer(); -void usbd_end(bool reset_ep, bool only_controller); -int usb_device_init(); -int usb_device_ep0_initialize(usb_gadget_type type); -int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync); -int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read); -int usb_device_ep1_out_reading_finish(u32 *pending_bytes); -int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync); -int usb_device_ep1_in_writing_finish(u32 *pending_bytes); -bool usb_device_get_suspended(); +void usb_device_get_ops(usb_ops_t *ops); +void xusb_device_get_ops(usb_ops_t *ops); int usb_device_gadget_ums(usb_ctxt_t *usbs); int usb_device_gadget_hid(usb_ctxt_t *usbs); -bool usb_device_get_max_lun(u8 max_lun); -bool usb_device_get_hid_report(); -u32 usb_device_get_port_status(); #endif \ No newline at end of file diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c new file mode 100644 index 0000000..e33ca44 --- /dev/null +++ b/bdk/usb/xusbd.c @@ -0,0 +1,2022 @@ +/* + * eXtensible USB Device driver (XDCI) for Tegra X1 + * + * Copyright (c) 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 . + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define XUSB_TRB_SLOTS 16 //! TODO: Consider upping it. +#define XUSB_LINK_TRB_IDX (XUSB_TRB_SLOTS - 1) +#define XUSB_LAST_TRB_IDX (XUSB_TRB_SLOTS - 1) + +#define EP_DONT_RING 0 +#define EP_RING_DOORBELL 1 + +typedef enum { + XUSB_FULL_SPEED = 1, + XUSB_HIGH_SPEED = 3, + XUSB_SUPER_SPEED = 4 +} xusb_speed_t; + +typedef enum { + EP_DISABLED = 0, + EP_RUNNING = 1, + EP_HALTED = 2, + EP_STOPPED = 3, + EP_ERROR = 4 +} xusb_ep_status_t; + +typedef enum { + EP_TYPE_ISOC_OUT = 1, + EP_TYPE_BULK_OUT = 2, + EP_TYPE_INTR_OUT = 3, + EP_TYPE_CNTRL = 4, + EP_TYPE_ISOC_IN = 5, + EP_TYPE_BULK_IN = 6, + EP_TYPE_INTR_IN = 7 +} xusb_ep_type_t; + +typedef enum { + XUSB_DEFAULT = 0, + XUSB_ADDRESSED_STS_WAIT = 1, + XUSB_ADDRESSED = 2, + XUSB_CONFIGURED_STS_WAIT = 3, + XUSB_CONFIGURED = 4, + + XUSB_LUN_CONFIGURED_STS_WAIT = 5, + XUSB_LUN_CONFIGURED = 6, + XUSB_HID_CONFIGURED_STS_WAIT = 7, + XUSB_HID_CONFIGURED = 8, + + // XUSB_CONNECTED = , + // XUSB_DISCONNECTED = , + // XUSB_RESET = , + // XUSB_SUSPENDED = , +} xusb_dev_state_t; + +typedef enum { + XUSB_TRB_NONE = 0, + XUSB_TRB_NORMAL = 1, + XUSB_TRB_DATA = 3, + XUSB_TRB_STATUS = 4, + XUSB_TRB_LINK = 6, + XUSB_TRB_TRANSFER = 32, + XUSB_TRB_PORT_CHANGE = 34, + XUSB_TRB_SETUP = 63, +} xusb_trb_type_t; + +typedef enum { + XUSB_COMP_INVALID = 0, + XUSB_COMP_SUCCESS = 1, + XUSB_COMP_DATA_BUFFER_ERROR = 2, + XUSB_COMP_BABBLE_DETECTED_ERROR = 3, + XUSB_COMP_USB_TRANSACTION_ERROR = 4, + XUSB_COMP_TRB_ERROR = 5, + XUSB_COMP_STALL_ERROR = 6, + XUSB_COMP_RESOURCE_ERROR = 7, + XUSB_COMP_BANDWIDTH_ERROR = 8, + XUSB_COMP_NO_SLOTS_AVAILABLE_ERROR = 9, + XUSB_COMP_INVALID_STREAM_TYPE_ERROR = 10, + XUSB_COMP_SLOT_NOT_ENABLED_ERROR = 11, + XUSB_COMP_EP_DISABLED_ERROR = 12, + XUSB_COMP_SHORT_PKT = 13, + XUSB_COMP_RING_UNDERRUN = 14, + XUSB_COMP_RING_OVERRUN = 15, + XUSB_COMP_VF_EVENT_RING_FULL_ERROR = 16, + XUSB_COMP_PARAMETER_ERROR = 17, + XUSB_COMP_BANDWIDTH_OVERRUN_ERROR = 18, + XUSB_COMP_CONTEXT_STATE_ERROR = 19, + XUSB_COMP_NO_PING_RESPONSE_ERROR = 20, + XUSB_COMP_EVENT_RING_FULL_ERROR = 21, + XUSB_COMP_INCOMPATIBLE_DEVICE_ERROR = 22, + XUSB_COMP_MISSED_SERVICE_ERROR = 23, + XUSB_COMP_COMMAND_RING_STOPPED = 24, + XUSB_COMP_COMMAND_ABORTED = 25, + XUSB_COMP_STOPPED = 26, + XUSB_COMP_STOPPED_LENGTH_INVALID = 27, + XUSB_COMP_STOPPED_SHORT_PACKET = 28, + XUSB_COMP_EXIT_LATENCY_LARGE_ERROR = 29, + XUSB_COMP_ISOCH_BUFFER_OVERRUN = 31, + XUSB_COMP_EVENT_LOST_ERROR = 32, + XUSB_COMP_UNDEFINED_ERROR = 33, + XUSB_COMP_INVALID_STREAM_ID_ERROR = 34, + XUSB_COMP_SECONDARY_BANDWIDTH_ERROR = 35, + XUSB_COMP_SPLIT_TRANSACTION_ERROR = 36, + + XUSB_COMP_CODE_STREAM_NUMP_ERROR = 219, + XUSB_COMP_PRIME_PIPE_RECEIVED = 220, + XUSB_COMP_HOST_REJECTED = 221, + XUSB_COMP_CTRL_DIR_ERROR = 222, + XUSB_COMP_CTRL_SEQ_NUM_ERROR = 223 +} xusb_comp_code_t; + +typedef struct _event_trb_t +{ + u32 rsvd0; + u32 rsvd1; + + u32 rsvd2:24; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvd3:9; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvd4:11; +} event_trb_t; + +typedef struct _transfer_event_trb_t { + u32 trb_pointer_lo; + u32 trb_pointer_hi; + + u32 trb_tx_len:24; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvddw3_0:1; + u32 event_data:1; + u32 rsvddw3_1:7; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvddw3_2:11; +} transfer_event_trb_t; + +typedef struct _setup_event_trb_t +{ + usb_ctrl_setup_t ctrl_setup_data; + + u32 ctrl_seq_num:16; + u32 rsvddw2_0:8; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvddw3_0:9; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvddw3_1:11; +} setup_event_trb_t; + +typedef struct _status_trb_t +{ + u32 rsvd0; + u32 rsvd1; + + u32 rsvd2:22; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 rsvd3_0:2; + u32 chain:1; + u32 ioc:1; + u32 rsvd3_1:4; + u32 trb_type:6; + u32 dir:1; + u32 rsvd3_2:15; +} status_trb_t; + +typedef struct _normal_trb_t +{ + u32 databufptr_lo; + u32 databufptr_hi; + + u32 trb_tx_len:17; + u32 td_size:5; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 isp:1; + u32 no_snoop:1; + u32 chain:1; + u32 ioc:1; + u32 idt:1; + u32 rsvd0_0:2; + u32 bei:1; + u32 trb_type:6; + u32 rsvd0_1:16; +} normal_trb_t; + +typedef struct _data_trb_t +{ + u32 databufptr_lo; + u32 databufptr_hi; + + u32 trb_tx_len:17; + u32 td_size:5; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 isp:1; + u32 no_snoop:1; + u32 chain:1; + u32 ioc:1; + u32 rsvd0_0:4; + u32 trb_type:6; + u32 dir:1; + u32 rsvd0_1:15; +} data_trb_t; + +typedef struct _link_trb_t +{ + u32 rsvd0_0:4; + u32 ring_seg_ptrlo:28; + + u32 ring_seg_ptrhi; + + u32 rsvd1_0:22; + u32 interrupt_target:10; + + u32 cycle:1; + u32 toggle_cycle:1; + u32 rsvd3_0:2; + u32 chain:1; + u32 ioc:1; + u32 rsvd3_1:4; + u32 trb_type:6; + u32 rsvd3_2:16; +} link_trb_t; + +typedef struct _xusb_ep_ctx_t +{ + // Common context. + u32 ep_state:3; + u32 rsvddW0_0:5; + u32 mult:2; + u32 max_pstreams:5; + u32 lsa:1; + u32 interval:8; + u32 rsvddW0_1:8; + + u32 rsvddw1_0:1; + u32 cerr:2; + u32 ep_type:3; + u32 rsvddw1_1:1; + u32 hid:1; + u32 max_burst_size:8; + u32 max_packet_size:16; + + u32 dcs:1; + u32 rsvddw2_0:3; + u32 trd_dequeueptr_lo:28; + + u32 trd_dequeueptr_hi; + + u32 avg_trb_len:16; + u32 max_esit_payload:16; + + // Nvidia context. + u32 event_data_txlen_acc; + + u32 cprog:8; + u32 sbyte:7; + u32 tp:2; + u32 rec:1; + u32 cec:2; + u32 ced:1; + u32 hsp1:1; + u32 rty1:1; + u32 std:1; + u32 status:8; + + u32 data_offset; + + u32 scratch_pad0; + + u32 scratch_pad1; + + u32 cping:8; + u32 sping:8; + u32 toggle_cycle:2; + u32 no_snoop:1; + u32 ro:1; + u32 tlm:1; + u32 dlm:1; + u32 hsp2:1; + u32 rty2:1; + u32 stop_rec_req:8; + + u32 device_addr:8; + u32 hub_addr:8; + u32 root_port_num:8; + u32 slot_id:8; + + u32 routing_string:20; + u32 speed:4; + u32 lpu:1; + u32 mtt:1; + u32 hub:1; + u32 dci:5; + + u32 tthub_slot_id:8; + u32 ttport_num:8; + u32 ssf:4; + u32 sps:2; + u32 interrupt_target:10; + + u32 frz:1; + u32 end:1; + u32 elm:1; + u32 mrx:1; + u32 ep_linklo:28; + + u32 ep_linkhi; +} xusb_ep_ctx_t; + +typedef struct _xusbd_controller_t +{ + data_trb_t *cntrl_epenqueue_ptr; + data_trb_t *cntrl_epdequeue_ptr; + u32 cntrl_producer_cycle; + data_trb_t *bulkout_epenqueue_ptr; + data_trb_t *bulkout_epdequeue_ptr; + u32 bulkout_producer_cycle; + data_trb_t *bulkin_epenqueue_ptr; + data_trb_t *bulkin_epdequeue_ptr; + u32 bulkin_producer_cycle; + event_trb_t *event_enqueue_ptr; + event_trb_t *event_dequeue_ptr; + u32 event_ccs; + u32 device_state; + u32 bytes_remaining[2]; + u32 tx_count[2]; + u32 ctrl_seq_num; + u32 config_num; + u32 interface_num; + u32 wait_for_event_trb; + u32 port_speed; + + usb_desc_t *desc; + usb_gadget_type gadget; + + u8 max_lun; + bool max_lun_set; + bool bulk_reset_req; +} xusbd_controller_t; + +extern u32 hid_report_descriptor_jc_size; +extern u32 hid_report_descriptor_touch_size; +extern u8 hid_report_descriptor_jc[]; +extern u8 hid_report_descriptor_touch[]; +extern usb_desc_t usb_gadget_hid_jc_descriptors; +extern usb_desc_t usb_gadget_hid_touch_descriptors; +extern usb_desc_t usb_gadget_ums_descriptors; + +// All rings and EP context must be aligned to 0x10. +typedef struct _xusbd_event_queues_t +{ + event_trb_t xusb_event_ring_seg0[XUSB_TRB_SLOTS]; + event_trb_t xusb_event_ring_seg1[XUSB_TRB_SLOTS]; + data_trb_t xusb_cntrl_event_queue[XUSB_TRB_SLOTS]; + data_trb_t xusb_bulkin_event_queue[XUSB_TRB_SLOTS]; + data_trb_t xusb_bulkout_event_queue[XUSB_TRB_SLOTS]; + volatile xusb_ep_ctx_t xusb_ep_ctxt[4]; +} xusbd_event_queues_t; + +// Set event queues context to a 0x10 aligned address. +xusbd_event_queues_t *xusb_evtq = (xusbd_event_queues_t *)XUSB_RING_ADDR; + +xusbd_controller_t *usbd_xotg; +xusbd_controller_t usbd_xotg_controller_ctxt; + +static int _xusb_xhci_mask_wait(u32 reg, u32 mask, u32 val, u32 retries) +{ + do + { + if ((XUSB_DEV_XHCI(reg) & mask) == val) + return USB_RES_OK; + usleep(1); + --retries; + } + while (retries); + + return USB_ERROR_TIMEOUT; +} + +// Event rings aligned to 0x10 +static void _xusbd_ep_init_event_ring() +{ + memset(xusb_evtq->xusb_event_ring_seg0, 0, sizeof(xusb_evtq->xusb_event_ring_seg0)); + memset(xusb_evtq->xusb_event_ring_seg1, 0, sizeof(xusb_evtq->xusb_event_ring_seg1)); + + //! TODO USB3: enable pcie regulators. + + // Set Event Ring Segment 0 Base Address. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BALO) = (u32)xusb_evtq->xusb_event_ring_seg0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BAHI) = 0; + + // Set Event Ring Segment 1 Base Address. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BALO) = (u32)xusb_evtq->xusb_event_ring_seg1; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BAHI) = 0; + + // Set Event Ring Segment sizes. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERSTSZ) = (XUSB_TRB_SLOTS << 16) | XUSB_TRB_SLOTS; + + // Set Enqueue and Dequeue pointers. + usbd_xotg->event_enqueue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_ccs = 1; + + // Event Ring Enqueue Pointer. + u32 evt_ring_addr = (u32)xusb_evtq->xusb_event_ring_seg0 & 0xFFFFFFF0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xE) | evt_ring_addr | XCHI_ECS; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPHI) = 0; + + // Set Event Ring Dequeue Pointer. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF) | evt_ring_addr; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPHI) = 0; +} + +static void _xusb_ep_set_type_and_metrics(u32 ep_idx, volatile xusb_ep_ctx_t *ep_ctxt) +{ + usb_ep_descr_t *ep_desc = NULL; + usb_ep_descr_t *endpoints = usbd_xotg->desc->cfg->endpoint; + + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + // Set EP type. + ep_ctxt->ep_type = EP_TYPE_CNTRL; + + // Set max packet size based on port speed. + ep_ctxt->avg_trb_len = 8; + ep_ctxt->max_packet_size = 64; //! TODO USB3: max_packet_size = 512. + break; + + case USB_EP_BULK_OUT: + // Set default EP type. + ep_ctxt->ep_type = EP_TYPE_BULK_OUT; + + // Check configuration descriptor. + if (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class. + endpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t)); + + for (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++) + if (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_OUT) + { + ep_desc = &endpoints[i]; + break; + } + + // Set actual EP type. + if (ep_desc) + { + switch (ep_desc->bmAttributes) + { + case USB_EP_TYPE_ISO: + ep_ctxt->ep_type = EP_TYPE_ISOC_OUT; + break; + case USB_EP_TYPE_BULK: + ep_ctxt->ep_type = EP_TYPE_BULK_OUT; + break; + case USB_EP_TYPE_INTR: + ep_ctxt->ep_type = EP_TYPE_INTR_OUT; + break; + } + } + + // Set average TRB length. + //TODO: Use ep type instead (we don't expect to calculate avg per gadget)? + switch (usbd_xotg->gadget) + { + case USB_GADGET_UMS: + ep_ctxt->avg_trb_len = 3072; + break; + case USB_GADGET_HID_GAMEPAD: + case USB_GADGET_HID_TOUCHPAD: + ep_ctxt->avg_trb_len = 1024; + break; + default: + switch (usbd_xotg->port_speed) + { + case XUSB_SUPER_SPEED: + ep_ctxt->avg_trb_len = 1024; + break; + case XUSB_HIGH_SPEED: + case XUSB_FULL_SPEED: + ep_ctxt->avg_trb_len = 512; + break; + } + break; + } + + // Set max burst rate. + ep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3; + + // Set max packet size based on port speed. + if (usbd_xotg->port_speed == XUSB_SUPER_SPEED) + { + ep_ctxt->max_packet_size = 1024; + + //! TODO USB3: + // If ISO or INTR EP, set Max Esit Payload size. + // ep_ctxt->max_burst_size = bMaxBurst; + //if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + // ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + ep_ctxt->max_packet_size = 512; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else + { + ep_ctxt->max_packet_size = 64; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size; + } + break; + + case USB_EP_BULK_IN: + // Set default EP type. + ep_ctxt->ep_type = EP_TYPE_BULK_IN; + + // Check configuration descriptor. + if (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class. + endpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t)); + + for (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++) + if (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_IN) + { + ep_desc = &endpoints[i]; + break; + } + + // Set actual EP type. + if (ep_desc) + { + switch (ep_desc->bmAttributes) + { + case USB_EP_TYPE_ISO: + ep_ctxt->ep_type = EP_TYPE_ISOC_IN; + break; + case USB_EP_TYPE_BULK: + ep_ctxt->ep_type = EP_TYPE_BULK_IN; + break; + case USB_EP_TYPE_INTR: + ep_ctxt->ep_type = EP_TYPE_INTR_IN; + break; + } + } + + // Set average TRB length. + //TODO: Use ep type instead (we don't expect to calculate avg per gadget)? + switch (usbd_xotg->gadget) + { + case USB_GADGET_UMS: + ep_ctxt->avg_trb_len = 3072; + break; + case USB_GADGET_HID_GAMEPAD: + case USB_GADGET_HID_TOUCHPAD: + ep_ctxt->avg_trb_len = 16; // Normal interrupt avg is 1024KB. + break; + default: + switch (usbd_xotg->port_speed) + { + case XUSB_SUPER_SPEED: + ep_ctxt->avg_trb_len = 1024; + break; + case XUSB_HIGH_SPEED: + case XUSB_FULL_SPEED: + ep_ctxt->avg_trb_len = 512; + break; + } + break; + } + + // Set max burst rate. + ep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3; + + // Set max packet size based on port speed. + if (usbd_xotg->port_speed == XUSB_SUPER_SPEED) + { + ep_ctxt->max_packet_size = 1024; + + //! TODO USB3: + // If ISO or INTR EP, set Max Esit Payload size. + // ep_ctxt->max_burst_size = bMaxBurst; + //if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + // ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + ep_ctxt->max_packet_size = 512; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else + { + ep_ctxt->max_packet_size = 64; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size; + } + break; + } +} + +static int _xusb_ep_init_context(u32 ep_idx) +{ + link_trb_t *link_trb; + + if (ep_idx > USB_EP_BULK_IN) + return USB_ERROR_INIT; + + if (ep_idx == XUSB_EP_CTRL_OUT) + ep_idx = XUSB_EP_CTRL_IN; + + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx]; + memset((void *)ep_ctxt, 0, sizeof(xusb_ep_ctx_t)); + + ep_ctxt->ep_state = EP_RUNNING; + ep_ctxt->dcs = 1; + ep_ctxt->cec = 3; + ep_ctxt->cerr = 3; + ep_ctxt->max_burst_size = 0; + + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + usbd_xotg->cntrl_producer_cycle = 1; + usbd_xotg->cntrl_epenqueue_ptr = xusb_evtq->xusb_cntrl_event_queue; + usbd_xotg->cntrl_epdequeue_ptr = xusb_evtq->xusb_cntrl_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_cntrl_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + + case USB_EP_BULK_OUT: + usbd_xotg->bulkout_producer_cycle = 1; + usbd_xotg->bulkout_epenqueue_ptr = xusb_evtq->xusb_bulkout_event_queue; + usbd_xotg->bulkout_epdequeue_ptr = xusb_evtq->xusb_bulkout_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_bulkout_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + + case USB_EP_BULK_IN: + usbd_xotg->bulkin_producer_cycle = 1; + usbd_xotg->bulkin_epenqueue_ptr = xusb_evtq->xusb_bulkin_event_queue; + usbd_xotg->bulkin_epdequeue_ptr = xusb_evtq->xusb_bulkin_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_bulkin_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + } + + return USB_RES_OK; +} + +static int _xusbd_ep_initialize(u32 ep_idx) +{ + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + case XUSB_EP_CTRL_OUT: + return _xusb_ep_init_context(XUSB_EP_CTRL_IN); + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + _xusb_ep_init_context(ep_idx); + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_RELOAD) = BIT(ep_idx); + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_RELOAD, BIT(ep_idx), 0, 1000); + if (!res) + { + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_PAUSE) &= ~BIT(ep_idx); + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~BIT(ep_idx); + } + return res; + default: + return USB_ERROR_INIT; + } +} + +static void _xusb_init_phy() +{ + // Configure and enable PLLU. + clock_enable_pllu(); + + // Enable IDDQ control by software and disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1; + + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + clock_enable_utmipll(); + + // Set UTMIP misc config. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFE8) | 0x2000008 | 0x20 | 2; + usleep(2); + + // Set OTG PAD0 calibration. + u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); + // Set HS_CURR_LEVEL. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) & 0xFFFFFFC0) | (fuse_usb_calib & 0x3F); + // Set TERM_RANGE_ADJ and RPD_CTRL. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) & 0x83FFFF87) | ((fuse_usb_calib & 0x780) >> 4) | ((u32)(FUSE(FUSE_USB_CALIB_EXT) << 27) >> 1); + + // Set VREG_LEV to 1. + XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) & 0xFFFFFE3F) | 0x80; + + // Disable power down on usb2 ports pads. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) &= 0xDBFFFFFF; // Clear pad power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) &= 0xFFFFFFFB; // Clear pad dr power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0) &= 0xFFFFFFFE; // Clear charging power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_0) &= 0xFFFFF7FF; // Clear bias power down. + (void)XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1); // Commit write. + + // Enable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_USB2_TRK); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. + + // Set tracking parameters and trigger it. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000; + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x51E000; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000; + usleep(3); + + // Re-trigger it. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x51E000; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) |= 0x4000000; + + // Disable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK); + + // Wait for XUSB PHY to stabilize. + usleep(30); +} + +static void _xusbd_init_device_clocks() +{ + // Disable reset to PLLU_OUT1 + CLOCK(CLK_RST_CONTROLLER_PLLU_OUTA) |= 1; + usleep(2); + + // Enable XUSB device clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_XUSB_DEV); + + // Set XUSB device core clock source to PLLP for a 102MHz result. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) & 0x1FFFFF00) | (1 << 29) | 6; + usleep(2); + + // Set XUSB Full-Speed logic clock source to FO 48MHz. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) & 0x1FFFFFFF) | (2 << 29); + + // Enable XUSB Super-Speed logic clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB_SS); + + // Set XUSB Super-Speed logic clock source to HSIC 480MHz for 120MHz result and source FS logic clock from Super-Speed. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) & 0x1FFFFF00) | (3 << 29) | 6; + + // Clear reset to XUSB device and Super-Speed logic. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_XUSB_DEV); + usleep(2); +} + +int xusb_device_init() +{ + ///////////////////////////////////////////////// + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD); + ///////////////////////////////////////////////// + + + // Enable XUSB clock and clear Reset to XUSB Pad Control. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL); + usleep(2); + + // USB2 Pads to XUSB. + XUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) = + (XUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) & ~(PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK)) | + PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB; + + // Initialize XUSB controller PHY. + _xusb_init_phy(); + + // Set USB2.0 Port 0 to device mode. + XUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) & ~PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK) | PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV; + + //! TODO USB3 + // // Set USB3.0 Port 0 cap to device. + // XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) & ~PADCTL_SS_PORT_CAP_0_PORT1_CAP_MASK) | PADCTL_SS_PORT_CAP_0_PORT1_CAP_DEVICE_ONLY; + + // Set Super Speed Port 0 to USB2 Port 0. + XUSB_PADCTL(XUSB_PADCTL_SS_PORT_MAP) &= ~PADCTL_SS_PORT_MAP_PORT0_MASK; // 0: USB2_PORT0 + + // Power Up ID Wake up and Vbus Wake Up for UTMIP + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; + usleep(1); + + // Initialize device clocks. + _xusbd_init_device_clocks(); + + // Enable AHB redirect for access to IRAM for Event/EP ring buffers. + mc_enable_ahb_redirect(); // can be skipped if IRAM is not used///////////////// + + // Enable XUSB device IPFS. + XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI; + + // Configure PCI and BAR0 address space. + XUSB_DEV_PCI(XUSB_CFG_1) |= CFG_1_BUS_MASTER | CFG_1_MEMORY_SPACE | CFG_1_IO_SPACE; + usleep(1); + XUSB_DEV_PCI(XUSB_CFG_4) = XUSB_DEV_BASE | CFG_4_ADDRESS_TYPE_32_BIT; + + // Mask SATA interrupt to MCORE. + XUSB_DEV_DEV(XUSB_DEV_INTR_MASK) |= DEV_INTR_MASK_IP_INT_MASK; + + // AHB USB performance cfg. + //TODO: Doesn't help.. +/* + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB3) |= AHB_GIZMO_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB3; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = + MEM_PREFETCH_ENABLE | MEM_PREFETCH_USB3_MST_ID | MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles. +*/ + + // Initialize context. + usbd_xotg = &usbd_xotg_controller_ctxt; + memset(usbd_xotg, 0, sizeof(xusbd_controller_t)); + + // Initialize event and EP rings. + _xusbd_ep_init_event_ring(); + memset(xusb_evtq->xusb_cntrl_event_queue, 0, sizeof(xusb_evtq->xusb_cntrl_event_queue)); + memset(xusb_evtq->xusb_bulkin_event_queue, 0, sizeof(xusb_evtq->xusb_bulkin_event_queue)); + memset(xusb_evtq->xusb_bulkout_event_queue, 0, sizeof(xusb_evtq->xusb_bulkout_event_queue)); + + // Initialize Control EP. + int res = _xusbd_ep_initialize(XUSB_EP_CTRL_IN); + if (res) + return USB_ERROR_INIT; + + // Enable events and interrupts. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_IE | XHCI_CTRL_LSE; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) = (u32)xusb_evtq->xusb_ep_ctxt & 0xFFFFFFF0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPHI) = 0; + + //! TODO USB3: + // XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) |= DEV_XHCI_PORTHALT_STCHG_INTR_EN; + + return USB_RES_OK; +} + +static int _xusb_queue_trb(int ep_idx, void *trb, bool ring_doorbell) +{ + int res = USB_RES_OK; + data_trb_t *next_trb; + link_trb_t *link_trb; + + // Copy TRB and advance Enqueue list. + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + memcpy(usbd_xotg->cntrl_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->cntrl_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + link_trb->toggle_cycle = 1; + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + usbd_xotg->cntrl_producer_cycle ^= 1; + } + usbd_xotg->cntrl_epenqueue_ptr = next_trb; + break; + + case USB_EP_BULK_OUT: + memcpy(usbd_xotg->bulkout_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->bulkout_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->bulkout_producer_cycle & 1; + link_trb->toggle_cycle = 1; + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + usbd_xotg->bulkout_producer_cycle ^= 1; + } + usbd_xotg->bulkout_epenqueue_ptr = next_trb; + break; + + case USB_EP_BULK_IN: + memcpy(usbd_xotg->bulkin_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->bulkin_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->bulkin_producer_cycle & 1; + link_trb->toggle_cycle = 1; + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + usbd_xotg->bulkin_producer_cycle ^= 1; + } + usbd_xotg->bulkin_epenqueue_ptr = next_trb; + break; + + case XUSB_EP_CTRL_OUT: + default: + res = XUSB_ERROR_INVALID_EP; + break; + } + + // Ring doorbell. + if (ring_doorbell) + { + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + u32 target_id = (ep_idx << 8) & 0xFFFF; + if (ep_idx == XUSB_EP_CTRL_IN) + target_id |= usbd_xotg->ctrl_seq_num << 16; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_DB) = target_id; + } + + return res; +} + +static void _xusb_create_status_trb(status_trb_t *trb, usb_dir_t direction) +{ + trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_STATUS; + trb->dir = direction; +} + +static void _xusb_create_normal_trb(normal_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction) +{ + u8 producer_cycle; + + trb->databufptr_lo = (u32)buf; + trb->databufptr_hi = 0; + + trb->trb_tx_len = len; + + // Single TRB transfer. + trb->td_size = 0; + trb->chain = 0; + + if (direction == USB_DIR_IN) + producer_cycle = usbd_xotg->bulkin_producer_cycle & 1; + else + producer_cycle = usbd_xotg->bulkout_producer_cycle & 1; + + trb->cycle = producer_cycle; + trb->isp = 1; // Enable interrupt on short packet. + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_NORMAL; +} + +static void _xusb_create_data_trb(data_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction) +{ + trb->databufptr_lo = (u32)buf; + trb->databufptr_hi = 0; + + trb->trb_tx_len = len; + + // Single TRB transfer. + trb->td_size = 0; + trb->chain = 0; + + trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + trb->isp = 1; // Enable interrupt on short packet. + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_DATA; + trb->dir = direction; +} + +static int _xusb_issue_status_trb(usb_dir_t direction) +{ + int res = USB_RES_OK; + status_trb_t trb = {0}; + + if (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr || direction == USB_DIR_OUT) + { + _xusb_create_status_trb(&trb, direction); + res = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL); + usbd_xotg->wait_for_event_trb = XUSB_TRB_STATUS; + } + + return res; +} + +static int _xusb_issue_normal_trb(u8 *buf, u32 len, usb_dir_t direction) +{ + normal_trb_t trb = {0}; + + _xusb_create_normal_trb(&trb, buf, len, direction); + int ep_idx = USB_EP_BULK_IN; + if (direction == USB_DIR_OUT) + ep_idx = USB_EP_BULK_OUT; + int res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL); + if (!res) + usbd_xotg->wait_for_event_trb = XUSB_TRB_NORMAL; + + return res; +} + +static int _xusb_issue_data_trb(u8 *buf, u32 len, usb_dir_t direction) +{ + data_trb_t trb = {0}; + + int res = USB_RES_OK; + if (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr) + { + _xusb_create_data_trb(&trb, buf, len, direction); + res = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL); + if (!res) + usbd_xotg->wait_for_event_trb = XUSB_TRB_DATA; + } + return res; +} + +int xusb_set_ep_stall(u32 endpoint, int ep_stall) +{ + int ep_idx = BIT(endpoint); + if (ep_stall) + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_idx; + else + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_idx; + + // Wait for EP status to change. + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_idx, ep_idx, 1000); + if (res) + return res; + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_idx; + + return USB_RES_OK; +} + +static int _xusb_handle_transfer_event(transfer_event_trb_t *trb) +{ + // Advance dequeue list. + data_trb_t *next_trb; + switch (trb->ep_id) + { + case XUSB_EP_CTRL_IN: + next_trb = &usbd_xotg->cntrl_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->cntrl_epdequeue_ptr = next_trb; + break; + case USB_EP_BULK_OUT: + next_trb = &usbd_xotg->bulkout_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->bulkout_epdequeue_ptr = next_trb; + break; + case USB_EP_BULK_IN: + next_trb = &usbd_xotg->bulkin_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->bulkin_epdequeue_ptr = next_trb; + break; + default: + // Should never happen. + break; + } + + // Handle completion code. + switch (trb->comp_code) + { + case XUSB_COMP_SUCCESS: + case XUSB_COMP_SHORT_PKT: + switch (trb->ep_id) + { + case XUSB_EP_CTRL_IN: + if (usbd_xotg->wait_for_event_trb == XUSB_TRB_DATA) + return _xusb_issue_status_trb(USB_DIR_OUT); + else if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS) + { + if (usbd_xotg->device_state == XUSB_ADDRESSED_STS_WAIT) + usbd_xotg->device_state = XUSB_ADDRESSED; + else if (usbd_xotg->device_state == XUSB_CONFIGURED_STS_WAIT) + usbd_xotg->device_state = XUSB_CONFIGURED; + else if (usbd_xotg->device_state == XUSB_LUN_CONFIGURED_STS_WAIT) + usbd_xotg->device_state = XUSB_LUN_CONFIGURED; + else if (usbd_xotg->device_state == XUSB_HID_CONFIGURED_STS_WAIT) + usbd_xotg->device_state = XUSB_HID_CONFIGURED; + } + break; + + case USB_EP_BULK_IN: + usbd_xotg->bytes_remaining[USB_DIR_IN] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_IN])/////////// + usbd_xotg->tx_count[USB_DIR_IN]--; + + // If bytes remaining for a Bulk IN transfer, return error. + if (trb->trb_tx_len) + return XUSB_ERROR_XFER_BULK_IN_RESIDUE; + break; + + case USB_EP_BULK_OUT: + // If short packet and Bulk OUT, it's not an error because we prime EP for 4KB. + usbd_xotg->bytes_remaining[USB_DIR_OUT] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_OUT])/////////// + usbd_xotg->tx_count[USB_DIR_OUT]--; + break; + } + return USB_RES_OK; +/* + case XUSB_COMP_USB_TRANSACTION_ERROR: + case XUSB_COMP_TRB_ERROR: + case XUSB_COMP_RING_UNDERRUN: + case XUSB_COMP_RING_OVERRUN: + case XUSB_COMP_CTRL_DIR_ERROR: // Redefined. + xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL); + return USB_RES_OK; +*/ + case XUSB_COMP_CTRL_DIR_ERROR: + return XUSB_ERROR_XFER_DIR; + + case XUSB_COMP_CTRL_SEQ_NUM_ERROR: + return XUSB_ERROR_SEQ_NUM; //! TODO: Can mean a new setup packet was received. + + default: // Every other completion code. + return USB_ERROR_XFER_ERROR; + } +} + +/* + * Other XUSB impl: + * CBT: PR, PRC, WPR, WRC, CSC, REQ, PLC, CEC. + * LNX: REQ, PRC PR, PRC & !PR, WRC, CSC, PLC, CEC. + * BRO: CSC, PR | PRC, WPR | WRC, REQ, PLC, CEC. + */ + +static int _xusb_handle_port_change() +{ + u32 res = USB_RES_OK; + u32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + u32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + + // Connect status change (CSC). + if (status & XHCI_PORTSC_CSC) + { + //! TODO: Check CCS. + // CCS check seems to be + // XHCI_PORTSC_CCS 1: device_state = XUSB_CONNECTED + // XHCI_PORTSC_CCS 0: device_state = XUSB_DISCONNECTED + // Always do XHCI_PORTSC_CSC bit clear. + + // Set port speed. + usbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10; + + // In case host does not support Super Speed, revert the control EP packet size. + if (usbd_xotg->port_speed != XUSB_SUPER_SPEED) + { + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN]; + ep_ctxt->avg_trb_len = 8; + ep_ctxt->max_packet_size = 64; + } + + // Clear CSC bit. + status |= XHCI_PORTSC_CSC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Port reset (PR), Port reset change (PRC). + if (status & XHCI_PORTSC_PR || status & XHCI_PORTSC_PRC) + { + //! TODO: + // XHCI_PORTSC_PR: device_state = XUSB_RESET + + //_disable_usb_wdt4(); + + //res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // unpatched0 + // if (res) return res; + _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // patched0 + + // Clear PRC bit. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PRC; + } + + // Warm Port Reset (WPR), Warm Port Reset Change (WRC). + if (status & XHCI_PORTSC_WPR || status & XHCI_PORTSC_WRC) + { + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_WRC, XHCI_PORTSC_WRC, 1000); + + // Clear WRC bit. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_WRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_WRC; + + //! TODO: WPR: device_state = XUSB_RESET + } + + // Handle Config Request (STCHG_REQ). + if (halt & XHCI_PORTHALT_STCHG_REQ) + { + // Clear Link Training Status. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) & ~XHCI_PORTHALT_HALT_LTSSM; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + } + + // Port link state change (PLC). + if (status & XHCI_PORTSC_PLC) + { + //! WAR: Sometimes port speed changes without a CSC event. Set again. + usbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10; + + // check PLS + // if U3 + // device_state = XUSB_SUSPENDED + // else if U0 and XUSB_SUSPENDED + // val = XUSB_DEV_XHCI_EP_PAUSE + // XUSB_DEV_XHCI_EP_PAUSE = 0 + // XUSB_DEV_XHCI_EP_STCHG = val; + + // Clear PLC bit. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PLC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PLC; + } + + // Port configuration link error (CEC). + if (status & XHCI_PORTSC_CEC) + { + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_CEC; + res = XUSB_ERROR_PORT_CFG; + } + + return res; +} + +static int _xusb_handle_get_ep_status(usb_ctrl_setup_t *ctrl_setup) +{ + static u8 xusb_ep_status_descriptor[2] = {0}; + + // Get EP context pointer. + volatile xusb_ep_ctx_t *ep_ctxt = (volatile xusb_ep_ctx_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) & 0xFFFFFFF0); + ep_ctxt = &ep_ctxt[ctrl_setup->wIndex]; + + xusb_ep_status_descriptor[0] = (ep_ctxt->ep_state == EP_HALTED) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK; + return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN); +} + +static int _xusb_handle_get_class_request(usb_ctrl_setup_t *ctrl_setup) +{ + u8 _bRequest = ctrl_setup->bRequest; + u16 _wIndex = ctrl_setup->wIndex; + u16 _wValue = ctrl_setup->wValue; + u16 _wLength = ctrl_setup->wLength; + + bool valid_interface = _wIndex == usbd_xotg->interface_num; + bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0; + + if (!valid_interface || _wValue != 0 || _wLength != valid_len) + goto stall; + + switch (_bRequest) + { + case USB_REQUEST_BULK_RESET: + usbd_xotg->bulk_reset_req = true; + return _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS; + case USB_REQUEST_BULK_GET_MAX_LUN: + if (!usbd_xotg->max_lun_set) + goto stall; + usbd_xotg->device_state = XUSB_LUN_CONFIGURED_STS_WAIT; + return _xusb_issue_data_trb(&usbd_xotg->max_lun, 1, USB_DIR_IN); + } + +stall: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; +} + +static int _xusb_handle_get_descriptor(usb_ctrl_setup_t *ctrl_setup) +{ + u32 size; + void *descriptor; + + u32 wLength = ctrl_setup->wLength; + + u8 descriptor_type = ctrl_setup->wValue >> 8; + u8 descriptor_subtype = ctrl_setup->wValue & 0xFF; + + switch (descriptor_type) + { + case USB_DESCRIPTOR_DEVICE: + //! TODO USB3: Provide a super speed descriptor. +/* + u32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV); + usb_device_descriptor.idProduct = (soc_rev >> 8) & 0xFF; // chip_id. + usb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM. + usb_device_descriptor.bcdDevice = (soc_rev >> 16) & 0xF; // MINORREV. + usb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV. +*/ + descriptor = usbd_xotg->desc->dev; + size = usbd_xotg->desc->dev->bLength; + break; + case USB_DESCRIPTOR_CONFIGURATION: + //! TODO USB3: Provide a super speed descriptor. + if (usbd_xotg->gadget == USB_GADGET_UMS) + { + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes. + { + usbd_xotg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; // No burst. + usbd_xotg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; // No burst. + } + else // Full speed. 64 bytes. + { + usbd_xotg->desc->cfg->endpoint[0].wMaxPacketSize = 0x40; + usbd_xotg->desc->cfg->endpoint[1].wMaxPacketSize = 0x40; + } + } + else + { + usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_xotg->desc->cfg; + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x200; + tmp->endpoint[1].wMaxPacketSize = 0x200; + tmp->endpoint[0].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + } + else // Full speed. 64 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x40; + tmp->endpoint[1].wMaxPacketSize = 0x40; + tmp->endpoint[0].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + } + } + descriptor = usbd_xotg->desc->cfg; + size = usbd_xotg->desc->cfg->config.wTotalLength; + break; + case USB_DESCRIPTOR_STRING: + switch (descriptor_subtype) + { + case 1: + descriptor = usbd_xotg->desc->vendor; + size = usbd_xotg->desc->vendor[0]; + break; + case 2: + descriptor = usbd_xotg->desc->product; + size = usbd_xotg->desc->product[0]; + break; + case 3: + descriptor = usbd_xotg->desc->serial; + size = usbd_xotg->desc->serial[0]; + break; + case 0xEE: + descriptor = usbd_xotg->desc->ms_os; + size = usbd_xotg->desc->ms_os->bLength; + break; + default: + descriptor = usbd_xotg->desc->lang_id; + size = 4; + break; + } + break; + case USB_DESCRIPTOR_DEVICE_QUALIFIER: + if (!usbd_xotg->desc->dev_qual) + { + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + usbd_xotg->desc->dev_qual->bNumOtherConfigs = 0; + descriptor = usbd_xotg->desc->dev_qual; + size = usbd_xotg->desc->dev_qual->bLength; + break; + case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + if (!usbd_xotg->desc->cfg_other) + { + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + usbd_xotg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; + usbd_xotg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; + } + else + { + usbd_xotg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x200; + usbd_xotg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x200; + } + descriptor = usbd_xotg->desc->cfg_other; + size = usbd_xotg->desc->cfg_other->config.wTotalLength; + break; + case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: + descriptor = usbd_xotg->desc->dev_bot; + size = usbd_xotg->desc->dev_bot->wTotalLength; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + + if (wLength < size) + size = wLength; + + return _xusb_issue_data_trb(descriptor, size, USB_DIR_IN); +} + +static void _xusb_handle_set_request_dev_address(usb_ctrl_setup_t *ctrl_setup) +{ + u32 addr = ctrl_setup->wValue & 0xFF; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) & 0x80FFFFFF) | (addr << 24); + xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN].device_addr = addr; + + _xusb_issue_status_trb(USB_DIR_IN); + + usbd_xotg->device_state = XUSB_ADDRESSED_STS_WAIT; +} + +static void _xusb_handle_set_request_configuration(usb_ctrl_setup_t *ctrl_setup) +{ + u32 config_num = ctrl_setup->wValue; + if (!config_num) //TODO! we can change device_state here. + return; + + // Initialize BULK EPs. + _xusbd_ep_initialize(USB_EP_BULK_OUT); + _xusbd_ep_initialize(USB_EP_BULK_IN); + + // Device mode start. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_RUN; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_RC; + + _xusb_issue_status_trb(USB_DIR_IN); + + usbd_xotg->config_num = config_num; + usbd_xotg->device_state = XUSB_CONFIGURED_STS_WAIT; +} + +static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup) +{ + u32 size; + u8 *desc; + bool ep_stall = false; + bool transmit_data = false; + + u8 _bmRequestType = ctrl_setup->bmRequestType; + u8 _bRequest = ctrl_setup->bRequest; + u16 _wValue = ctrl_setup->wValue; + u16 _wIndex = ctrl_setup->wIndex; + u16 _wLength = ctrl_setup->wLength; + + static u8 xusb_dev_status_descriptor[2] = {USB_STATUS_DEV_SELF_POWERED, 0}; + static u8 xusb_interface_descriptor[4] = {0}; + static u8 xusb_configuration_descriptor[2] = {0}; + static u8 xusb_status_descriptor[2] = {0}; + + //gfx_printf("ctrl: %02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI; + u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI, 0, 1000); + if (res) + return res; + + switch (_bmRequestType) + { + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + if (_bRequest == USB_REQUEST_SET_ADDRESS) + _xusb_handle_set_request_dev_address(ctrl_setup); + else if (_bRequest == USB_REQUEST_SET_CONFIGURATION) + _xusb_handle_set_request_configuration(ctrl_setup); + return USB_RES_OK; // What about others. + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + usbd_xotg->interface_num = _wValue; + return _xusb_issue_status_trb(USB_DIR_IN); + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) + { + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + { + xusb_set_ep_stall(_wIndex, USB_EP_CFG_CLEAR); + return _xusb_issue_status_trb(USB_DIR_IN); + } + else if (_bRequest == USB_REQUEST_SET_FEATURE) + { + xusb_set_ep_stall(_wIndex, USB_EP_CFG_STALL); + return _xusb_issue_status_trb(USB_DIR_IN); + } + } + ep_stall = true; + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + return _xusb_handle_get_class_request(ctrl_setup); + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + switch (_bRequest) + { + case USB_REQUEST_GET_STATUS: + desc = xusb_dev_status_descriptor; + size = sizeof(xusb_dev_status_descriptor); + transmit_data = true; + break; + case USB_REQUEST_GET_DESCRIPTOR: + return _xusb_handle_get_descriptor(ctrl_setup); + case USB_REQUEST_GET_CONFIGURATION: + xusb_configuration_descriptor[0] = usbd_xotg->config_num; + desc = xusb_configuration_descriptor; + size = sizeof(xusb_configuration_descriptor); + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + if (_bRequest == USB_REQUEST_GET_INTERFACE) + { + desc = xusb_interface_descriptor; + size = sizeof(xusb_interface_descriptor); + xusb_interface_descriptor[0] = usbd_xotg->interface_num; + transmit_data = true; + } + else if (_bRequest == USB_REQUEST_GET_STATUS) + { + desc = xusb_status_descriptor; + size = sizeof(xusb_status_descriptor); + transmit_data = true; + } + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_xotg->gadget > USB_GADGET_UMS) + { + if (usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD) + { + desc = (u8 *)&hid_report_descriptor_jc; + size = hid_report_descriptor_jc_size; + } + else // USB_GADGET_HID_TOUCHPAD + { + desc = (u8 *)&hid_report_descriptor_touch; + size = hid_report_descriptor_touch_size; + } + transmit_data = true; + usbd_xotg->device_state = XUSB_HID_CONFIGURED_STS_WAIT; + } + else + ep_stall = true; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + if (_bRequest == USB_REQUEST_GET_STATUS) + return _xusb_handle_get_ep_status(ctrl_setup); + + ep_stall = true; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + return _xusb_handle_get_class_request(ctrl_setup); + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_INTERFACE): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE): + if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) + { + switch (_wIndex) + { + case USB_DESCRIPTOR_MS_COMPAT_ID: + desc = (u8 *)usbd_xotg->desc->ms_cid; + size = usbd_xotg->desc->ms_cid->dLength; + transmit_data = true; + break; + case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: + desc = (u8 *)usbd_xotg->desc->mx_ext; + size = usbd_xotg->desc->mx_ext->dLength; + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + } + else + ep_stall = true; + break; + + default: + ep_stall = true; + break; + } + + if (transmit_data) + { + memcpy((u8 *)USB_EP_CONTROL_BUF_ADDR, desc, size); + if (_wLength < size) + size = _wLength; + return _xusb_issue_data_trb((u8 *)USB_EP_CONTROL_BUF_ADDR, size, USB_DIR_IN); + } + + if (ep_stall) + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + + return USB_RES_OK; +} + +static int _xusb_ep_operation(u32 tries) +{ + usb_ctrl_setup_t setup_event; + volatile event_trb_t *event_trb; + setup_event_trb_t *setup_event_trb; + + // Wait for an interrupt event. + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_ST, XHCI_ST_IP, XHCI_ST_IP, tries); + if (res) + return res; + + // Clear interrupt status. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_IP; + + usbd_xotg->event_enqueue_ptr = (event_trb_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xFFFFFFF0); + event_trb = usbd_xotg->event_dequeue_ptr; + + // Check if cycle matches. + if ((event_trb->cycle & 1) != usbd_xotg->event_ccs) + return XUSB_ERROR_INVALID_CYCLE; + + while ((event_trb->cycle & 1) == usbd_xotg->event_ccs) + { + switch (event_trb->trb_type) + { + case XUSB_TRB_TRANSFER: + res = _xusb_handle_transfer_event((transfer_event_trb_t *)event_trb); + break; + case XUSB_TRB_PORT_CHANGE: + res = _xusb_handle_port_change(); + break; + case XUSB_TRB_SETUP: + setup_event_trb = (setup_event_trb_t *)event_trb; + memcpy(&setup_event, &setup_event_trb->ctrl_setup_data, sizeof(usb_ctrl_setup_t)); + usbd_xotg->ctrl_seq_num = setup_event_trb->ctrl_seq_num; + res = _xusbd_handle_ep0_control_transfer(&setup_event); + break; + default: + // TRB not supported. + break; + } + + // Check if last event TRB and reset to first one. + if (usbd_xotg->event_dequeue_ptr == &xusb_evtq->xusb_event_ring_seg1[XUSB_LAST_TRB_IDX]) + { + usbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_ccs ^= 1; + } + else // Advance dequeue to next event. + usbd_xotg->event_dequeue_ptr = &usbd_xotg->event_dequeue_ptr[1]; + + // Set next event. + event_trb = usbd_xotg->event_dequeue_ptr; + + // If events exceed the interrupt time, handle them next interrupt. + if (usbd_xotg->event_dequeue_ptr == usbd_xotg->event_enqueue_ptr) + break; + } + + // Clear Event Handler bit if enabled and set Dequeue pointer. + u32 erdp = XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF; + if (erdp & XHCI_ERDPLO_EHB) + erdp |= XHCI_ERDPLO_EHB; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = ((u32)usbd_xotg->event_dequeue_ptr & 0xFFFFFFF0) | erdp; + + return res; +} + +int xusb_device_enumerate(usb_gadget_type gadget) +{ + switch (gadget) + { + case USB_GADGET_UMS: + usbd_xotg->desc = &usb_gadget_ums_descriptors; + break; + case USB_GADGET_HID_GAMEPAD: + usbd_xotg->desc = &usb_gadget_hid_jc_descriptors; + break; + case USB_GADGET_HID_TOUCHPAD: + usbd_xotg->desc = &usb_gadget_hid_touch_descriptors; + break; + } + + usbd_xotg->gadget = gadget; + + // Disable Wake events. + XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_0) = 0; + XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_1) = 0; + + // Enable overrides for VBUS and ID. + XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~(PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK | PADCTL_USB2_VBUS_ID_SRC_MASK)) | + PADCTL_USB2_VBUS_ID_VBUS_OVR_EN | PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN; + + // Clear halt for LTSSM. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + + // Enable device mode. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_ENABLE; + + // Override access to High/Full Speed. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) & ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK) | XHCI_CFG_DEV_FE_PORTREGSEL_HSFS; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = + (XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & ~XHCI_PORTSC_PLS_MASK) | XHCI_PORTSC_LWS | XHCI_PORTSC_PLS_RXDETECT; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) &= ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK; + + // Enable VBUS and set ID to Float. + XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~PADCTL_USB2_VBUS_ID_OVR_MASK) | + PADCTL_USB2_VBUS_ID_OVR_FLOAT | PADCTL_USB2_VBUS_ID_VBUS_ON; + + usbd_xotg->wait_for_event_trb = XUSB_TRB_SETUP; + usbd_xotg->device_state = XUSB_DEFAULT; + + // Timeout if cable or communication isn't started in 1.5 minutes. + u32 timer = get_tmr_ms() + 90000; + while (true) + { + int res = _xusb_ep_operation(1000000); // 2s timeout. + if (res && res != USB_ERROR_TIMEOUT) + return res; + + if (usbd_xotg->device_state == XUSB_CONFIGURED) + break; + + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return USB_ERROR_USER_ABORT; + } + + return USB_RES_OK; +} + +void xusb_end(bool reset_ep, bool only_controller) +{ + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_XUSB_DEV); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_XUSB_DEV); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + mc_disable_ahb_redirect();/////////////////// +} + +int xusb_handle_ep0_ctrl_setup() +{ + /* + * EP0 Control handling is done by normal ep operation in XUSB. + * Here we handle the bulk reset only. + */ + if (usbd_xotg->bulk_reset_req) + { + usbd_xotg->bulk_reset_req = false; + return USB_RES_BULK_RESET; + } + + return USB_RES_OK; +} + +int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int res = USB_RES_OK; + usbd_xotg->tx_count[USB_DIR_OUT] = 0; + usbd_xotg->bytes_remaining[USB_DIR_OUT] = len; + _xusb_issue_normal_trb(buf, len, USB_DIR_OUT); + usbd_xotg->tx_count[USB_DIR_OUT]++; + + if (sync) + { + while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) + res = _xusb_ep_operation(1000000); // 2s timeout. + + if (bytes_read) + *bytes_read = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + } + + return res; +} + +int xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) +{ + if (len > USB_EP_BULK_OUT_MAX_XFER) + len = USB_EP_BULK_OUT_MAX_XFER; + + u32 bytes = 0; + *bytes_read = 0; + u8 *buf_curr = buf; + + while (len) + { + u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); + + int res = xusb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED); + if (res) + return res; + + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; + } + + return USB_RES_OK; +} + +int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) +{ + int res = USB_RES_OK; + while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) + res = _xusb_ep_operation(tries); + + if (pending_bytes) + *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + return res; +} + +int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + int res = USB_RES_OK; + usbd_xotg->tx_count[USB_DIR_IN] = 0; + usbd_xotg->bytes_remaining[USB_DIR_IN] = len; + _xusb_issue_normal_trb(buf, len, USB_DIR_IN); + usbd_xotg->tx_count[USB_DIR_IN]++; + + if (sync) + { + while (!res && usbd_xotg->tx_count[USB_DIR_IN]) + res = _xusb_ep_operation(1000000); // 2s timeout. + + if (bytes_written) + *bytes_written = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; + } + else + { + if ((usbd_xotg->port_speed == XUSB_FULL_SPEED && len == 64) || + (usbd_xotg->port_speed == XUSB_HIGH_SPEED && len == 512) || + (usbd_xotg->port_speed == XUSB_SUPER_SPEED && len == 1024)) + { + _xusb_issue_normal_trb(buf, 0, USB_DIR_IN); + usbd_xotg->tx_count[USB_DIR_IN]++; + } + } + + return res; +} + +int xusb_device_ep1_in_writing_finish(u32 *pending_bytes) +{ + int res = USB_RES_OK; + while (!res && usbd_xotg->tx_count[USB_DIR_IN]) + res = _xusb_ep_operation(1000000); // 2s timeout. + + if (pending_bytes) + *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; + + return res; +} + +bool xusb_device_get_port_in_sleep() +{ + // Ejection heuristic. + u32 link_mode = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & XHCI_PORTSC_PLS_MASK; + return (link_mode == XHCI_PORTSC_PLS_U3); +} + +bool xusb_device_class_send_max_lun(u8 max_lun) +{ + // Timeout if get MAX_LUN request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + usbd_xotg->max_lun = max_lun; + usbd_xotg->max_lun_set = true; + + // Wait for request and transfer start. + while (usbd_xotg->device_state != XUSB_LUN_CONFIGURED) + { + _xusb_ep_operation(500000); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + usbd_xotg->device_state = XUSB_CONFIGURED; + + return false; +} + +bool xusb_device_class_send_hid_report() +{ + // Timeout if get GET_HID_REPORT request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + // Wait for request and transfer start. + while (usbd_xotg->device_state != XUSB_HID_CONFIGURED) + { + _xusb_ep_operation(500000); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + usbd_xotg->device_state = XUSB_CONFIGURED; + + return false; +} + +void xusb_device_get_ops(usb_ops_t *ops) +{ + ops->usbd_flush_endpoint = NULL; + ops->usbd_set_ep_stall = xusb_set_ep_stall; + ops->usbd_handle_ep0_ctrl_setup = xusb_handle_ep0_ctrl_setup; + ops->usbd_end = xusb_end;////////////////// + ops->usb_device_init = xusb_device_init; + ops->usb_device_enumerate = xusb_device_enumerate; + ops->usb_device_class_send_max_lun = xusb_device_class_send_max_lun; + ops->usb_device_class_send_hid_report = xusb_device_class_send_hid_report; + ops->usb_device_get_suspended = xusb_device_get_port_in_sleep; + ops->usb_device_get_port_in_sleep = xusb_device_get_port_in_sleep; + + ops->usb_device_ep1_out_read = xusb_device_ep1_out_read; + ops->usb_device_ep1_out_read_big = xusb_device_ep1_out_read_big; + ops->usb_device_ep1_out_reading_finish = xusb_device_ep1_out_reading_finish; + ops->usb_device_ep1_in_write = xusb_device_ep1_in_write; + ops->usb_device_ep1_in_writing_finish = xusb_device_ep1_in_writing_finish; +} diff --git a/bdk/utils/btn.h b/bdk/utils/btn.h index f284748..ac191fa 100644 --- a/bdk/utils/btn.h +++ b/bdk/utils/btn.h @@ -20,10 +20,10 @@ #include -#define BTN_POWER (1 << 0) -#define BTN_VOL_DOWN (1 << 1) -#define BTN_VOL_UP (1 << 2) -#define BTN_SINGLE (1 << 7) +#define BTN_POWER BIT(0) +#define BTN_VOL_DOWN BIT(1) +#define BTN_VOL_UP BIT(2) +#define BTN_SINGLE BIT(7) u8 btn_read(); u8 btn_read_vol(); diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 9d85ca0..0300425 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -23,10 +23,12 @@ #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) +#define BIT(n) (1U << (n)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define DIV_ROUND_UP(a, b) ((a + b - 1) / b) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) #define LOG2(n) (32 - __builtin_clz(n) - 1) #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) @@ -60,17 +62,25 @@ typedef volatile unsigned char vu8; typedef volatile unsigned short vu16; typedef volatile unsigned int vu32; +#ifdef __aarch64__ +typedef u64 uptr; +#else /* __arm__ or __thumb__ */ +typedef u32 uptr; +#endif + static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; typedef int bool; #define true 1 #define false 0 -#define BOOT_CFG_AUTOBOOT_EN (1 << 0) -#define BOOT_CFG_FROM_LAUNCH (1 << 1) -#define BOOT_CFG_SEPT_RUN (1 << 7) +#define BOOT_CFG_AUTOBOOT_EN BIT(0) +#define BOOT_CFG_FROM_LAUNCH BIT(1) +#define BOOT_CFG_FROM_ID BIT(2) +#define BOOT_CFG_TO_EMUMMC BIT(3) +#define BOOT_CFG_SEPT_RUN BIT(7) -#define EXTRA_CFG_DUMP_EMUMMC (1 << 0) +#define EXTRA_CFG_DUMP_EMUMMC BIT(0) typedef struct __attribute__((__packed__)) _boot_cfg_t { @@ -82,8 +92,10 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t { struct { - char id[8]; + char id[8]; // 7 char ASCII null teminated. + char emummc_path[0x78]; // emuMMC/XXX, ASCII null teminated. }; + u8 ums; // nyx_ums_type. u8 xt_str[0x80]; }; } boot_cfg_t; diff --git a/bdk/utils/util.c b/bdk/utils/util.c index dd10781..e5cd868 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -135,7 +135,7 @@ void panic(u32 val) void reboot_normal() { sd_end(); - reconfig_hw_workaround(false, 0); + hw_reinit_workaround(false, 0); panic(0x21); // Bypass fuse programming in package1. } @@ -143,7 +143,7 @@ void reboot_normal() void reboot_rcm() { sd_end(); - reconfig_hw_workaround(false, 0); + hw_reinit_workaround(false, 0); PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; @@ -152,10 +152,27 @@ void reboot_rcm() bpmp_halt(); } +void reboot_full() +{ + sd_end(); + hw_reinit_workaround(false, 0); + + // Enable soft reset wake event. + u8 reg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2); + reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK; + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg); + + // Do a soft reset. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST); + + while (true) + bpmp_halt(); +} + void power_off() { sd_end(); - reconfig_hw_workaround(false, 0); + hw_reinit_workaround(false, 0); // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 948e02c..20df76f 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -23,21 +23,23 @@ typedef enum { - NYX_CFG_BIS = (1 << 5), - NYX_CFG_UMS = (1 << 6), - NYX_CFG_DUMP = (1 << 7), + NYX_CFG_BIS = BIT(5), + NYX_CFG_UMS = BIT(6), + NYX_CFG_DUMP = BIT(7), } nyx_cfg_t; typedef enum { - ERR_LIBSYS_LP0 = (1 << 0), - ERR_SYSOLD_NYX = (1 << 1), - ERR_SYSOLD_MTC = (1 << 2), - ERR_EXCEPT_ENB = (1 << 31), + ERR_LIBSYS_LP0 = BIT(0), + ERR_SYSOLD_NYX = BIT(1), + ERR_LIBSYS_MTC = BIT(2), + ERR_SD_BOOT_EN = BIT(3), + ERR_L4T_KERNEL = BIT(24), + ERR_EXCEPTION = BIT(31), } hekate_errors_t; -#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ - ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) +#define byte_swap_32(num) ((((num) >> 24) & 0xff) | (((num) << 8) & 0xff0000) | \ + (((num) >> 8 )& 0xff00) | (((num) << 24) & 0xff000000)) typedef struct _cfg_op_t { @@ -71,6 +73,7 @@ void msleep(u32 ms); void panic(u32 val); void reboot_normal(); void reboot_rcm(); +void reboot_full(); void power_off(); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); u32 crc32_calc(u32 crc, const u8 *buf, u32 len); diff --git a/source/config.c b/source/config.c index 7168e5b..254095e 100644 --- a/source/config.c +++ b/source/config.c @@ -23,6 +23,7 @@ #include "gfx/tui.h" #include #include +#include #include #include #include @@ -42,12 +43,14 @@ void set_default_configuration() h_cfg.autohosoff = 0; h_cfg.autonogc = 1; h_cfg.updater2p = 0; - h_cfg.brand = NULL; - h_cfg.tagline = NULL; + h_cfg.bootprotect = 0; h_cfg.errors = 0; + h_cfg.eks = NULL; h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; + h_cfg.aes_slots_new = false; h_cfg.rcm_patched = fuse_check_patched_rcm(); h_cfg.emummc_force_disable = false; + h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; sd_power_cycle_time_start = 0; } diff --git a/source/config.h b/source/config.h index 7833f4f..894cdf9 100644 --- a/source/config.h +++ b/source/config.h @@ -17,6 +17,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ +#include "hos/hos.h" #include typedef struct _hekate_config @@ -29,14 +30,16 @@ typedef struct _hekate_config u32 autohosoff; u32 autonogc; u32 updater2p; - char *brand; - char *tagline; + u32 bootprotect; // Global temporary config. + bool t210b01; bool se_keygen_done; bool sept_run; + bool aes_slots_new; bool emummc_force_disable; bool rcm_patched; u32 errors; + hos_eks_mbr_t *eks; } hekate_config; void set_default_configuration(); diff --git a/source/hos/fss.c b/source/hos/fss.c index 6ae5d8d..09896f9 100644 --- a/source/hos/fss.c +++ b/source/hos/fss.c @@ -19,6 +19,7 @@ #include #include "fss.h" +#include "hos.h" #include "../config.h" #include #include @@ -35,6 +36,7 @@ extern bool is_ipl_updated(void *buf, char *path, bool force); // FSS0 Magic and Meta header offset. #define FSS0_MAGIC 0x30535346 #define FSS0_META_OFFSET 0x4 +#define FSS0_VERSION_0_17_0 0x110000 // FSS0 Content Types. #define CNT_TYPE_FSP 0 @@ -48,9 +50,10 @@ extern bool is_ipl_updated(void *buf, char *path, bool force); #define CNT_TYPE_EMC 8 #define CNT_TYPE_KLD 9 // Kernel Loader. #define CNT_TYPE_KRN 10 // Kernel. +#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload. // FSS0 Content Flags. -#define CNT_FLAG0_EXPERIMENTAL (1 << 0) +#define CNT_FLAG0_EXPERIMENTAL BIT(0) // FSS0 Meta Header. typedef struct _fss_meta_t @@ -85,8 +88,12 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) bool stock = false; int sept_used = 0; + // Skip if stock and Exosphere and warmboot are not needed. if (!sept_ctxt) { + bool pkg1_old = ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620; + bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable; + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) { if (!strcmp("stock", kv->key)) @@ -94,7 +101,11 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) stock = true; } - if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable)) +#ifdef HOS_MARIKO_STOCK_SECMON + if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) +#else + if (stock && emummc_disabled && pkg1_old) +#endif return 1; } @@ -113,12 +124,25 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) // Check if valid FSS0 and parse it. if (fss_meta->magic == FSS0_MAGIC) { + bool mariko_not_supported = false; + if (h_cfg.t210b01 && (fss_meta->version < FSS0_VERSION_0_17_0)) + { + gfx_con.mute = false; + mariko_not_supported = true; + } + gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" "Max HOS supported: %d.%d.%d\n" "Unpacking and loading components.. ", fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); + if (mariko_not_supported) + { + EPRINTF("Mariko not supported on < 0.17.0!"); + goto fail; + } + if (!sept_ctxt) { ctxt->atmosphere = true; @@ -137,7 +161,7 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) continue; // If content is experimental and experimental flag is not enabled, skip it. - if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental) + if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_experimental) continue; // Parse content. @@ -154,14 +178,31 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) list_append(&ctxt->kip1_list, &mkip1->link); DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); break; + + case CNT_TYPE_KRN: + if (stock) + continue; + ctxt->kernel_size = curr_fss_cnt[i].size; + ctxt->kernel = content; + break; + case CNT_TYPE_EXO: ctxt->secmon_size = curr_fss_cnt[i].size; ctxt->secmon = content; break; + + case CNT_TYPE_EXF: + ctxt->exofatal_size = curr_fss_cnt[i].size; + ctxt->exofatal = content; + break; + case CNT_TYPE_WBT: + if (h_cfg.t210b01) + continue; ctxt->warmboot_size = curr_fss_cnt[i].size; ctxt->warmboot = content; break; + default: continue; } @@ -201,6 +242,7 @@ out: return (!sept_ctxt ? 1 : sept_used); } +fail: f_close(&fp); free(fss); diff --git a/source/hos/hos.h b/source/hos/hos.h index 4ad8747..b5900c6 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -42,6 +42,9 @@ #define HOS_PKG11_MAGIC 0x31314B50 #define HOS_EKS_MAGIC 0x30534B45 +// Use official Mariko secmon when in stock. +//#define HOS_MARIKO_STOCK_SECMON + typedef struct _exo_ctxt_t { bool fs_is_510; @@ -66,17 +69,17 @@ typedef struct _hos_eks_bis_keys_t typedef struct _hos_eks_mbr_t { u32 magic; - u8 enabled[6]; + u8 enabled[5]; u8 enabled_bis; - u8 rsvd; - u32 sbk_low; + u8 rsvd[2]; + u32 lot0; u8 dkg[0x10]; u8 dkk[0x10]; - hos_eks_keys_t keys[6]; + hos_eks_keys_t keys[5]; hos_eks_bis_keys_t bis_keys[3]; } hos_eks_mbr_t; -static_assert(sizeof(hos_eks_mbr_t) == 336, "HOS EKS size is wrong!"); +static_assert(sizeof(hos_eks_mbr_t) == 304, "HOS EKS size is wrong!"); typedef struct _launch_ctxt_t { @@ -90,6 +93,8 @@ typedef struct _launch_ctxt_t u32 warmboot_size; void *secmon; u32 secmon_size; + void *exofatal; + u32 exofatal_size; void *pkg2; u32 pkg2_size; @@ -97,6 +102,7 @@ typedef struct _launch_ctxt_t void *kernel; u32 kernel_size; + link_t kip1_list; char* kip1_patches; @@ -105,7 +111,7 @@ typedef struct _launch_ctxt_t bool debugmode; bool stock; bool atmosphere; - bool fss0_enable_experimental; + bool fss0_experimental; bool emummc_forced; exo_ctxt_t exo_ctx; diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 8f81334..23b25bd 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -45,7 +45,7 @@ static const pkg1_id_t _pkg1_ids[] = { const pkg1_id_t *pkg1_identify(u8 *pkg1) { for (u32 i = 0; _pkg1_ids[i].id; i++) - if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 8)) return &_pkg1_ids[i]; return NULL; } diff --git a/source/hos/sept.c b/source/hos/sept.c index fe9222f..3e65bdd 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -173,7 +173,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - reconfig_hw_workaround(false, 0); + hw_reinit_workaround(false, 0); (*sept)(); diff --git a/source/main.c b/source/main.c index f88a91c..961a572 100644 --- a/source/main.c +++ b/source/main.c @@ -31,7 +31,7 @@ #include #include #include -#include "soc/hw_init.h" +#include #include "storage/emummc.h" #include "storage/nx_emmc.h" #include @@ -126,12 +126,12 @@ int launch_payload(char *path) { reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); - reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); + hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); } else { reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); - reconfig_hw_workaround(true, 0); + hw_reinit_workaround(true, 0); } // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. @@ -326,7 +326,7 @@ extern void pivot_stack(u32 stack_top); void ipl_main() { // Do initial HW configuration. This is compatible with consecutive reruns without a reset. - config_hw(); + hw_init(); // Pivot the stack so we have enough space. pivot_stack(IPL_STACK_TOP); @@ -342,9 +342,12 @@ void ipl_main() // Set bootloader's default configuration. set_default_configuration(); - sd_mount(); + // Mount SD Card. + h_cfg.errors |= !sd_mount() ? ERR_SD_BOOT_EN : 0; - minerva_init(); + // Train DRAM and switch to max frequency. + if (minerva_init()) //!TODO: Add Tegra210B01 support to minerva. + h_cfg.errors |= ERR_LIBSYS_MTC; minerva_change_freq(FREQ_1600); display_init(); @@ -356,6 +359,15 @@ void ipl_main() display_backlight_pwm_init(); + if (h_cfg.t210b01) + { + gfx_printf("Mariko SOC detected!\nMariko is currently unsupported\nbut stay tuned..."); + gfx_printf("\n\n Press any button to power off."); + display_backlight_brightness(h_cfg.backlight, 1000); + btn_wait(); + power_off(); + } + // Overclock BPMP. bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); diff --git a/source/storage/emummc.c b/source/storage/emummc.c index 5253edc..baa4560 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -136,7 +136,7 @@ int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) FILINFO fno; emu_cfg.active_part = 0; - // Always init eMMC even when in emuMMC. eMMC is needed from theh emuMMC driver anyway. + // Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway. if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) return 2; @@ -276,7 +276,7 @@ int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) emu_cfg.active_part = partition; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - return sdmmc_storage_set_mmc_partition(storage, partition); + sdmmc_storage_set_mmc_partition(storage, partition); else if (emu_cfg.sector) return 1; else From 423a5640beeb942eca515567688a142b76a9e101 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 4 Dec 2020 13:07:46 -0700 Subject: [PATCH 087/166] keys: Break up dump_keys, begin Mariko support --- source/keys/key_sources.inl | 3 +- source/keys/keys.c | 345 +++++++++++++++++++----------------- source/keys/keys.h | 15 +- 3 files changed, 191 insertions(+), 172 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 5cb7f08..e5fddea 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -14,8 +14,7 @@ * along with this program. If not, see . */ -static u8 zeros[0x10] = {0}; - +// Sha256 hash of the null string. static u8 null_hash[0x20] = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; diff --git a/source/keys/keys.c b/source/keys/keys.c index a33a260..6ac19c4 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -71,7 +71,7 @@ static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { } // key functions -static int _key_exists(const void *data) { return memcmp(data, zeros, 0x10) != 0; }; +static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); @@ -94,6 +94,114 @@ static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; } +#define RELOC_META_OFF 0x7C + +static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { + sd_mount(); + if (!f_stat("sd:/sept/payload.bak", NULL)) { + if (f_unlink("sd:/sept/payload.bin")) + gfx_printf("%kNote: no payload.bin already in /sept\n", colors[(color_idx++) % 6]); + f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); + } + + if (!h_cfg.sept_run) { + // bundle lp0 fw for sept instead of loading it from SD as hekate does + sdram_lp0_save_params(sdram_get_params_patched()); + + FIL fp; + if (f_stat("sd:/sept", NULL)) { + EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); + return true; + } + // backup post-reboot payload + if (!f_stat("sd:/sept/payload.bin", NULL)) { + if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { + EPRINTF("Unable to backup payload.bin."); + return false; + } + } + // write self to payload.bin to run again when sept finishes + volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); + u32 payload_size = relocator->end - IPL_LOAD_ADDR; + if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { + EPRINTF("Unable to open /sept/payload.bin to write."); + return false; + } + gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); + if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { + EPRINTF("Unable to write self to /sept/payload.bin."); + f_close(&fp); + return false; + } + gfx_printf(" done"); + f_close(&fp); + gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); + gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); + gfx_printf("\n to /sept/payload.bak\n\n"); + gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); + sdmmc_storage_end(&emmc_storage); + if (!reboot_to_sept((u8 *)tsec_fw, tsec_size, kb)) { + return false; + } + } else { + se_aes_key_read(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, out_key, AES_128_KEY_SIZE); + } + + return true; +} + +static bool _handle_tsec(tsec_ctxt_t *tsec_ctxt, u32 kb, void *out_master_key, void *out_tsec_keys, u32 out_tsec_keys_size) { + tsec_ctxt->fw = _find_tsec_fw(tsec_ctxt->pkg1); + if (!tsec_ctxt->fw) { + EPRINTF("Unable to locate TSEC firmware."); + return false; + } + + minerva_periodic_training(); + + tsec_ctxt->size = _get_tsec_fw_size((tsec_key_data_t *)(tsec_ctxt->fw + TSEC_KEY_DATA_OFFSET)); + if (tsec_ctxt->size > PKG1_MAX_SIZE) { + EPRINTF("Unexpected TSEC firmware size."); + return false; + } + + if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.t210b01) { + if (!_handle_sept(tsec_ctxt->fw, tsec_ctxt->size, kb, out_master_key)) { + return false; + } + } + + if (kb == KB_FIRMWARE_VERSION_620) { + u8 *tsec_paged = (u8 *)page_alloc(3); + memcpy(tsec_paged, tsec_ctxt->fw, tsec_ctxt->size); + tsec_ctxt->fw = tsec_paged; + } + + int res = 0; + u32 retries = 0; + + mc_disable_ahb_redirect(); + + while (tsec_query(out_tsec_keys, kb, tsec_ctxt) < 0) { + memset(out_tsec_keys, 0, out_tsec_keys_size); + retries++; + if (retries > 15) { + res = -1; + break; + } + } + + mc_enable_ahb_redirect(); + + if (res < 0) { + EPRINTFARGS("ERROR %x dumping TSEC.\n", res); + return false; + } + + TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); + return true; +} + static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { FIL fp; u64 br = buf_size; @@ -221,33 +329,32 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return true; } -#define RELOC_META_OFF 0x7C - void dump_keys() { - u8 temp_key[0x10], - bis_key[4][0x20] = {0}, - device_key[0x10] = {0}, - device_key_4x[0x10] = {0}, - sd_seed[0x10] = {0}, + u8 temp_key[AES_128_KEY_SIZE], + bis_key[4][AES_128_KEY_SIZE * 2] = {0}, + device_key[AES_128_KEY_SIZE] = {0}, + device_key_4x[AES_128_KEY_SIZE] = {0}, + sd_seed[AES_128_KEY_SIZE] = {0}, // FS-related keys - header_key[0x20] = {0}, - save_mac_key[0x10] = {0}, + header_key[AES_128_KEY_SIZE * 2] = {0}, + save_mac_key[AES_128_KEY_SIZE] = {0}, // other sysmodule keys - eticket_rsa_kek[0x10] = {0}, - eticket_rsa_kek_personalized[0x10] = {0}, - ssl_rsa_kek[0x10] = {0}, + eticket_rsa_kek[AES_128_KEY_SIZE] = {0}, + eticket_rsa_kek_personalized[AES_128_KEY_SIZE] = {0}, + ssl_rsa_kek[AES_128_KEY_SIZE] = {0}, // keyblob-derived families - keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, + keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, + keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, + package1_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; + key_area_key[3][KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, + master_kek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, + master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, + package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, + titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, + tsec_keys[AES_128_KEY_SIZE * 2] = {0}; - keyblob_t keyblob[KB_FIRMWARE_VERSION_600+1] = {0}; + keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1] = {0}; sd_mount(); @@ -264,9 +371,7 @@ void dump_keys() { start_time = get_tmr_us(); u32 begin_time = get_tmr_us(); - u32 retries = 0; - tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; if (emummc_storage_init_mmc(&emmc_storage, &sdmmc)) { @@ -291,113 +396,25 @@ void dump_keys() { goto out_wait; } - tsec_ctxt.fw = _find_tsec_fw(pkg1); - if (!tsec_ctxt.fw) { - EPRINTF("Unable to locate TSEC firmware."); - goto out_wait; - } - - minerva_periodic_training(); - - tsec_ctxt.pkg1 = pkg1; - tsec_ctxt.size = _get_tsec_fw_size((tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_OFFSET)); - if (tsec_ctxt.size > PKG1_MAX_SIZE) { - EPRINTF("Unexpected TSEC firmware size."); - goto out_wait; - } - u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { - sd_mount(); - if (!f_stat("sd:/sept/payload.bak", NULL)) { - if (f_unlink("sd:/sept/payload.bin")) - gfx_printf("%kNote: no payload.bin already in /sept\n", colors[(color_idx++) % 6]); - f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); - } - - if (!h_cfg.sept_run) { - // bundle lp0 fw for sept instead of loading it from SD as hekate does - sdram_lp0_save_params(sdram_get_params_patched()); - - FIL fp; - if (f_stat("sd:/sept", NULL)) { - EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); - goto get_tsec; - } - // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) { - if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { - EPRINTF("Unable to backup payload.bin."); - goto out_wait; - } - } - // write self to payload.bin to run again when sept finishes - volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); - u32 payload_size = relocator->end - IPL_LOAD_ADDR; - if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { - EPRINTF("Unable to open /sept/payload.bin to write."); - goto out_wait; - } - gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); - if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - f_close(&fp); - goto out_wait; - } - gfx_printf(" done"); - f_close(&fp); - gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); - gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); - gfx_printf("\n to /sept/payload.bak\n\n"); - gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); - sdmmc_storage_end(&emmc_storage); - if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) - goto out_wait; - } else { - se_aes_key_read(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, master_key[KB_FIRMWARE_VERSION_MAX], 0x10); - } - } - -get_tsec: ; - u8 tsec_keys[0x10 * 2] = {0}; - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size); - tsec_ctxt.fw = tsec_paged; - } - - int res = 0; - - mc_disable_ahb_redirect(); - - while (tsec_query(tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) { - memset(tsec_keys, 0x00, 0x20); - retries++; - if (retries > 15) { - res = -1; - break; + if (!h_cfg.t210b01) { + tsec_ctxt_t tsec_ctxt; + tsec_ctxt.pkg1 = pkg1; + if (!_handle_tsec(&tsec_ctxt, pkg1_id->kb, master_key[KB_FIRMWARE_VERSION_MAX], tsec_keys, sizeof(tsec_keys))) { + free(pkg1); + goto out_wait; } } free(pkg1); - mc_enable_ahb_redirect(); - - if (res < 0) { - EPRINTFARGS("ERROR %x dumping TSEC.\n", res); - goto out_wait; - } - - TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); - // Master key derivation // on firmware 6.2.0 only, tsec_query delivers the tsec_root_key - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { - se_aes_key_set(8, tsec_keys + 0x10, 0x10); // mkek6 = unwrap(mkeks6, tsecroot) + if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + AES_128_KEY_SIZE)) { + se_aes_key_set(8, tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, master_kek[6], 0x10); // mkey = unwrap(mkek, mks) + se_aes_key_set(8, master_kek[6], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mks) se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source); } @@ -405,10 +422,10 @@ get_tsec: ; // derive all lower master keys in case keyblobs are bad if (_key_exists(master_key[pkg1_id->kb])) { for (u32 i = pkg1_id->kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], 0x10); + se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); } - se_aes_key_set(8, master_key[0], 0x10); + se_aes_key_set(8, master_key[0], AES_128_KEY_SIZE); se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); if (_key_exists(temp_key)) { EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); @@ -418,16 +435,16 @@ get_tsec: ; // handle sept version differences for (u32 kb = KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { for (u32 i = kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], 0x10); + se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); } - se_aes_key_set(8, master_key[0], 0x10); + se_aes_key_set(8, master_key[0], AES_128_KEY_SIZE); se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); if (!_key_exists(temp_key)) { break; } - memcpy(master_key[kb-1], master_key[kb], 0x10); - memset(master_key[kb], 0, 0x10); + memcpy(master_key[kb-1], master_key[kb], AES_128_KEY_SIZE); + memset(master_key[kb], 0, AES_128_KEY_SIZE); } if (_key_exists(temp_key)) { EPRINTF("Unable to derive master keys via sept."); @@ -438,14 +455,14 @@ get_tsec: ; u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; - u8 keyblob_mac[0x10] = {0}; + u8 keyblob_mac[AES_128_KEY_SIZE] = {0}; u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; se_aes_key_set(8, tsec_keys, sizeof(tsec_keys) / 2); se_aes_key_set(9, sbk, sizeof(sbk)); if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { - EPRINTF("Unable to read keyblob."); + EPRINTF("Unable to read keyblobs."); } for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { @@ -492,8 +509,8 @@ get_tsec: ; if (key_generation) { _get_device_key(8, temp_key, key_generation, device_key_4x, master_key[0]); } else - memcpy(temp_key, device_key, 0x10); - se_aes_key_set(8, temp_key, 0x10); + memcpy(temp_key, device_key, AES_128_KEY_SIZE); + se_aes_key_set(8, temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); @@ -529,7 +546,7 @@ get_tsec: ; _generate_kek(8, key_area_key_sources[j], master_key[i], aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); } - se_aes_key_set(8, master_key[i], 0x10); + se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source); se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); } @@ -546,12 +563,12 @@ get_tsec: ; // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; _generate_kek(7, eticket_rsa_kekek_source, master_key[0], temp_key, NULL); se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, eticket_rsa_kek_source); - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; _generate_kek(7, ssl_rsa_kek_source_x, master_key[0], temp_key, NULL); se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_rsa_kek_source_y); @@ -559,18 +576,18 @@ get_tsec: ; // Set BIS keys. // PRODINFO/PRODINFOF - se_aes_key_set(0, bis_key[0] + 0x00, 0x10); - se_aes_key_set(1, bis_key[0] + 0x10, 0x10); + se_aes_key_set(0, bis_key[0] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(1, bis_key[0] + 0x10, AES_128_KEY_SIZE); // SAFE - se_aes_key_set(2, bis_key[1] + 0x00, 0x10); - se_aes_key_set(3, bis_key[1] + 0x10, 0x10); + se_aes_key_set(2, bis_key[1] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(3, bis_key[1] + 0x10, AES_128_KEY_SIZE); // SYSTEM/USER - se_aes_key_set(4, bis_key[2] + 0x00, 0x10); - se_aes_key_set(5, bis_key[2] + 0x10, 0x10); + se_aes_key_set(4, bis_key[2] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(5, bis_key[2] + 0x10, AES_128_KEY_SIZE); // Set header key for NCA decryption. - se_aes_key_set(8, header_key + 0x00, 0x10); - se_aes_key_set(9, header_key + 0x10, 0x10); + se_aes_key_set(8, header_key + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(9, header_key + 0x10, AES_128_KEY_SIZE); if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { EPRINTF("Unable to set partition."); @@ -605,7 +622,7 @@ get_tsec: ; goto get_titlekeys; } // get sd seed verification vector - if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { + if (f_read(&fp, temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); goto get_titlekeys; @@ -660,9 +677,9 @@ get_titlekeys: if (keypair_generation) { keypair_generation--; - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - u8 temp_device_key[0x10] = {0}; + u8 temp_device_key[AES_128_KEY_SIZE] = {0}; _get_device_key(7, temp_device_key, keypair_generation, device_key_4x, master_key[0]); _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, temp_key, NULL); se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek_personalized, eticket_rsa_kek_source); @@ -748,10 +765,10 @@ key_output: ; SAVE_KEY(package2_key_source); SAVE_KEY(per_console_key_source); SAVE_KEY(retail_specific_aes_key_source); - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; SAVE_KEY_VAR(rsa_oaep_kek_generation_source, temp_key); - for (u32 i = 0; i < 0x10; i++) + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; SAVE_KEY_VAR(rsa_private_kek_generation_source, temp_key); SAVE_KEY(save_mac_kek_source); @@ -770,9 +787,9 @@ key_output: ; SAVE_KEY(ssl_rsa_kek_source_y); SAVE_KEY_FAMILY(titlekek, 0); SAVE_KEY(titlekek_source); - _save_key("tsec_key", tsec_keys, 0x10, text_buffer); + _save_key("tsec_key", tsec_keys, AES_128_KEY_SIZE, text_buffer); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - _save_key("tsec_root_key", tsec_keys + 0x10, 0x10, text_buffer); + _save_key("tsec_root_key", tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); @@ -797,10 +814,10 @@ key_output: ; titlekey_text_buffer_t *titlekey_text = (titlekey_text_buffer_t *)text_buffer; for (u32 i = 0; i < _titlekey_count; i++) { - for (u32 j = 0; j < 0x10; j++) + for (u32 j = 0; j < AES_128_KEY_SIZE; j++) sprintf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); sprintf(titlekey_text[i].equals, " = "); - for (u32 j = 0; j < 0x10; j++) + for (u32 j = 0; j < AES_128_KEY_SIZE; j++) sprintf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); sprintf(titlekey_text[i].newline, "\n"); } @@ -847,7 +864,7 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) return; - se_aes_key_set(ks, master_key, 0x10); + se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, kek_seed); se_aes_unwrap_key(ks, ks, key_source); if (key_seed && _key_exists(key_seed)) @@ -856,28 +873,28 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key) { if (revision < KB_FIRMWARE_VERSION_400) - memcpy(out_device_key, device_key, 0x10); + memcpy(out_device_key, device_key, AES_128_KEY_SIZE); revision -= KB_FIRMWARE_VERSION_400; - u8 temp_key[0x10] = {0}; - se_aes_key_set(ks, device_key, 0x10); - se_aes_crypt_ecb(ks, 0, temp_key, 0x10, device_master_key_source_sources[revision], 0x10); - se_aes_key_set(ks, master_key, 0x10); + u8 temp_key[AES_128_KEY_SIZE] = {0}; + se_aes_key_set(ks, device_key, AES_128_KEY_SIZE); + se_aes_crypt_ecb(ks, 0, temp_key, AES_128_KEY_SIZE, device_master_key_source_sources[revision], AES_128_KEY_SIZE); + se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, device_master_kek_sources[revision]); - se_aes_crypt_ecb(ks, 0, out_device_key, 0x10, temp_key, 0x10); + se_aes_crypt_ecb(ks, 0, out_device_key, AES_128_KEY_SIZE, temp_key, AES_128_KEY_SIZE); } static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { - u8 plaintext[0x100] = {0}, ciphertext[0x100] = {0}, work[0x100] = {0}; + u8 plaintext[RSA_2048_KEY_SIZE] = {0}, ciphertext[RSA_2048_KEY_SIZE] = {0}, work[RSA_2048_KEY_SIZE] = {0}; // 0xCAFEBABE plaintext[0xfc] = 0xca; plaintext[0xfd] = 0xfe; plaintext[0xfe] = 0xba; plaintext[0xff] = 0xbe; - se_rsa_key_set(0, modulus, 0x100, private_exponent, 0x100); - se_rsa_exp_mod(0, ciphertext, 0x100, plaintext, 0x100); + se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, private_exponent, RSA_2048_KEY_SIZE); + se_rsa_exp_mod(0, ciphertext, RSA_2048_KEY_SIZE, plaintext, RSA_2048_KEY_SIZE); - se_rsa_key_set(0, modulus, 0x100, public_exponent, 4); - se_rsa_exp_mod(0, work, 0x100, ciphertext, 0x100); + se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, public_exponent, 4); + se_rsa_exp_mod(0, work, RSA_2048_KEY_SIZE, ciphertext, RSA_2048_KEY_SIZE); - return !memcmp(plaintext, work, 0x100); + return !memcmp(plaintext, work, RSA_2048_KEY_SIZE); } diff --git a/source/keys/keys.h b/source/keys/keys.h index ae6ead4..4e5d3ba 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -19,13 +19,16 @@ #include +#define AES_128_KEY_SIZE 16 +#define RSA_2048_KEY_SIZE 256 + // only tickets of type Rsa2048Sha256 are expected typedef struct { u32 signature_type; // always 0x10004 - u8 signature[0x100]; + u8 signature[RSA_2048_KEY_SIZE]; u8 sig_padding[0x3C]; char issuer[0x40]; - u8 titlekey_block[0x100]; + u8 titlekey_block[RSA_2048_KEY_SIZE]; u8 format_version; u8 titlekey_type; u16 ticket_version; @@ -59,8 +62,8 @@ typedef struct { } titlekey_buffer_t; typedef struct { - u8 private_exponent[0x100]; - u8 modulus[0x100]; + u8 private_exponent[RSA_2048_KEY_SIZE]; + u8 modulus[RSA_2048_KEY_SIZE]; u8 public_exponent[4]; u8 reserved[0x14]; u64 device_id; @@ -68,9 +71,9 @@ typedef struct { } rsa_keypair_t; typedef struct { - u8 master_kek[0x10]; + u8 master_kek[AES_128_KEY_SIZE]; u8 data[0x70]; - u8 package1_key[0x10]; + u8 package1_key[AES_128_KEY_SIZE]; } keyblob_t; typedef struct { From 1f77c50975d1e74b09bff82384e486882a232108 Mon Sep 17 00:00:00 2001 From: shchmue Date: Fri, 4 Dec 2020 18:28:05 -0700 Subject: [PATCH 088/166] keys: More refactoring --- source/hos/sept.c | 1 - source/keys/key_sources.inl | 40 +-- source/keys/keys.c | 508 ++++++++++++++++++------------------ source/keys/keys.h | 30 +++ 4 files changed, 299 insertions(+), 280 deletions(-) diff --git a/source/hos/sept.c b/source/hos/sept.c index 3e65bdd..5e6ef73 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -105,7 +105,6 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) } } - if (!fss0_sept_used) { // Copy sept-primary. diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index e5fddea..8a23b96 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -28,7 +28,7 @@ static const u8 keyblob_key_source[][0x10] = { {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 }; -static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = { +static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 @@ -36,7 +36,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 }; -static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = { +static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ @@ -65,7 +65,7 @@ static const u8 titlekek_source[0x10] = { static const u8 retail_specific_aes_key_source[0x10] = { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; -// from Package1ldr (or Secure_Monitor on 6.2.0) +// from Package1ldr (or Secure_Monitor on 6.2.0+) static const u8 keyblob_mac_key_source[0x10] = { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; static const u8 master_key_source[0x10] = { @@ -74,8 +74,14 @@ static const u8 per_console_key_source[0x10] = { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; static const u8 device_master_key_source_kek_source[0x10] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; -static const u8 mariko_master_kek_source[0x10] = { - 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}; +static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] = { + {0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56}, // 6.0.0. + {0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE}, // 6.2.0. + {0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A}, // 7.0.0. + {0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23}, // 8.1.0. + {0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, // 9.0.0. + {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. +}; static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ @@ -119,15 +125,12 @@ static const u8 aes_key_generation_source[0x10] = { static const u8 bis_kek_source[0x10] = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; static const u8 bis_key_source[3][0x20] = { - { - 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, - 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, - { - 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, - 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, - { - 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, - 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} + {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, + 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, + {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, + 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, + {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, + 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; static const u8 header_kek_source[0x10] = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}; @@ -135,12 +138,9 @@ static const u8 header_key_source[0x20] = { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}; static const u8 key_area_key_sources[3][0x10] = { - { - 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application - { - 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean - { - 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system + {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application + {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean + {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system }; static const u8 save_mac_kek_source[0x10] = { 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 6ac19c4..5f83a57 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -20,7 +20,6 @@ #include #include #include "../gfx/tui.h" -#include "../hos/hos.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/sept.h" @@ -96,6 +95,32 @@ static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { #define RELOC_META_OFF 0x7C +static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { + if (emummc_storage_init_mmc(&emmc_storage, sdmmc)) { + EPRINTF("Unable to init MMC."); + return NULL; + } + TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); + + // Read package1. + u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { + EPRINTF("Unable to set partition."); + return NULL; + } + if (!emummc_storage_read(&emmc_storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { + EPRINTF("Unable to read pkg1."); + return NULL; + } + *pkg1_id = pkg1_identify(pkg1); + if (!*pkg1_id) { + EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); + return NULL; + } + + return pkg1; +} + static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { @@ -150,7 +175,7 @@ static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { return true; } -static bool _handle_tsec(tsec_ctxt_t *tsec_ctxt, u32 kb, void *out_master_key, void *out_tsec_keys, u32 out_tsec_keys_size) { +static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx_t *keys) { tsec_ctxt->fw = _find_tsec_fw(tsec_ctxt->pkg1); if (!tsec_ctxt->fw) { EPRINTF("Unable to locate TSEC firmware."); @@ -165,13 +190,11 @@ static bool _handle_tsec(tsec_ctxt_t *tsec_ctxt, u32 kb, void *out_master_key, v return false; } - if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.t210b01) { - if (!_handle_sept(tsec_ctxt->fw, tsec_ctxt->size, kb, out_master_key)) { + if (kb >= KB_FIRMWARE_VERSION_700) { + if (!_handle_sept(tsec_ctxt->fw, tsec_ctxt->size, kb, keys->master_key[KB_FIRMWARE_VERSION_MAX])) { return false; } - } - - if (kb == KB_FIRMWARE_VERSION_620) { + } else if (kb == KB_FIRMWARE_VERSION_620) { u8 *tsec_paged = (u8 *)page_alloc(3); memcpy(tsec_paged, tsec_ctxt->fw, tsec_ctxt->size); tsec_ctxt->fw = tsec_paged; @@ -182,8 +205,8 @@ static bool _handle_tsec(tsec_ctxt_t *tsec_ctxt, u32 kb, void *out_master_key, v mc_disable_ahb_redirect(); - while (tsec_query(out_tsec_keys, kb, tsec_ctxt) < 0) { - memset(out_tsec_keys, 0, out_tsec_keys_size); + while (tsec_query(keys->tsec_keys, kb, tsec_ctxt) < 0) { + memset(keys->tsec_keys, 0, sizeof(keys->tsec_keys)); retries++; if (retries > 15) { res = -1; @@ -202,6 +225,156 @@ static bool _handle_tsec(tsec_ctxt_t *tsec_ctxt, u32 kb, void *out_master_key, v return true; } +static void _derive_master_keys_post_620_erista(u32 pkg1_kb, key_derivation_ctx_t *keys) { + u8 temp_key[AES_128_KEY_SIZE]; + // on firmware 6.2.0 only, the tsec_root_key is available + if (pkg1_kb == KB_FIRMWARE_VERSION_620 && _key_exists(keys->tsec_keys + AES_128_KEY_SIZE)) { + se_aes_key_set(8, keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) + se_aes_crypt_block_ecb(8, 0, keys->master_kek[6], master_kek_sources[0]); + se_aes_key_set(8, keys->master_kek[6], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mks) + se_aes_crypt_block_ecb(8, 0, keys->master_key[6], master_key_source); + } + + if (pkg1_kb >= KB_FIRMWARE_VERSION_620) { + // derive all lower master keys in case keyblobs are bad + // handle sept version differences + for (u32 kb = pkg1_kb == KB_FIRMWARE_VERSION_620 ? KB_FIRMWARE_VERSION_620 : KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { + for (u32 i = kb; i > 0; i--) { + se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); + } + se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); + if (!_key_exists(temp_key)) { + break; + } + memcpy(keys->master_key[kb - 1], keys->master_key[kb], AES_128_KEY_SIZE); + memset(keys->master_key[kb], 0, AES_128_KEY_SIZE); + } + if (_key_exists(temp_key)) { + EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_kb); + memset(keys->master_key, 0, sizeof(keys->master_key)); + } + } +} + +static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { + u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); + encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; + u8 keyblob_mac[AES_128_KEY_SIZE] = {0}; + keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); + keys->sbk[1] = FUSE(FUSE_PRIVATE_KEY1); + keys->sbk[2] = FUSE(FUSE_PRIVATE_KEY2); + keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); + se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); + se_aes_key_set(9, keys->sbk, sizeof(keys->sbk)); + + if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { + EPRINTF("Unable to read keyblobs."); + } + + for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { + minerva_periodic_training(); + se_aes_crypt_block_ecb(8, 0, keys->keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) + se_aes_crypt_block_ecb(9, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) + se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); + se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) + if (i == 0) { + se_aes_crypt_block_ecb(7, 0, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) + se_aes_crypt_block_ecb(7, 0, keys->device_key_4x, device_master_key_source_kek_source); + } + + // verify keyblob is not corrupt + se_aes_key_set(10, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i])); + se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); + if (memcmp(current_keyblob, keyblob_mac, sizeof(keyblob_mac)) != 0) { + EPRINTFARGS("Keyblob %x corrupt.", i); + continue; + } + + // decrypt keyblobs + se_aes_key_set(6, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); + se_aes_crypt_ctr(6, &keys->keyblob[i], sizeof(keyblob_t), ¤t_keyblob->key_data, sizeof(keyblob_t), current_keyblob->iv); + + memcpy(keys->package1_key[i], keys->keyblob[i].package1_key, sizeof(keys->package1_key[i])); + memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); + se_aes_key_set(7, keys->master_kek[i], sizeof(keys->master_kek[i])); + if (!_key_exists(keys->master_key[i])) { + se_aes_crypt_block_ecb(7, 0, keys->master_key[i], master_key_source); + } + } + free(keyblob_block); +} + +static void _derive_bis_keys(key_derivation_ctx_t *keys) { + /* key = unwrap(source, wrapped_key): + key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key + */ + minerva_periodic_training(); + u32 key_generation = fuse_read_odm_keygen_rev(); + if (key_generation) + key_generation--; + + if (_key_exists(keys->device_key)) { + if (key_generation) { + _get_device_key(8, keys->temp_key, key_generation, keys->device_key_4x, keys->master_key[0]); + } else + memcpy(keys->temp_key, keys->device_key, AES_128_KEY_SIZE); + se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); + se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_source[0] + 0x10); + // kek = generate_kek(bkeks, devkey, aeskek, aeskey) + _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_source[1] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_source[2] + 0x00); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_source[2] + 0x10); + memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); + } +} + +static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_count) { + if (_key_exists(keys->master_key[0])) { + _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x00, header_key_source + 0x00); + se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x10, header_key_source + 0x10); + } + + if (_key_exists(keys->device_key)) { + _generate_kek(8, save_mac_kek_source, keys->device_key, aes_kek_generation_source, NULL); + se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); + } + + if (_key_exists(keys->master_key[*derivable_key_count])) { + *derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1; + } + for (u32 i = 0; i < *derivable_key_count; i++) { + if (!_key_exists(keys->master_key[i])) + continue; + for (u32 j = 0; j < 3; j++) { + _generate_kek(8, key_area_key_sources[j], keys->master_key[i], aes_kek_generation_source, NULL); + se_aes_crypt_block_ecb(8, 0, keys->key_area_key[j][i], aes_key_generation_source); + } + se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->package2_key[i], package2_key_source); + se_aes_crypt_block_ecb(8, 0, keys->titlekek[i], titlekek_source); + } + + // derive eticket_rsa_kek and ssl_rsa_kek + if (_key_exists(keys->master_key[0])) { + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + _generate_kek(7, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek, eticket_rsa_kek_source); + + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + _generate_kek(7, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); + } +} + static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { FIL fp; u64 br = buf_size; @@ -330,31 +503,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title } void dump_keys() { - u8 temp_key[AES_128_KEY_SIZE], - bis_key[4][AES_128_KEY_SIZE * 2] = {0}, - device_key[AES_128_KEY_SIZE] = {0}, - device_key_4x[AES_128_KEY_SIZE] = {0}, - sd_seed[AES_128_KEY_SIZE] = {0}, - // FS-related keys - header_key[AES_128_KEY_SIZE * 2] = {0}, - save_mac_key[AES_128_KEY_SIZE] = {0}, - // other sysmodule keys - eticket_rsa_kek[AES_128_KEY_SIZE] = {0}, - eticket_rsa_kek_personalized[AES_128_KEY_SIZE] = {0}, - ssl_rsa_kek[AES_128_KEY_SIZE] = {0}, - // keyblob-derived families - keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, - keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, - package1_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE] = {0}, - // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, - master_kek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, - master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, - package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, - titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE] = {0}, - tsec_keys[AES_128_KEY_SIZE * 2] = {0}; - - keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1] = {0}; + key_derivation_ctx_t keys; sd_mount(); @@ -370,190 +519,48 @@ void dump_keys() { color_idx = 0; start_time = get_tmr_us(); - u32 begin_time = get_tmr_us(); + u32 start_whole_operation_time = get_tmr_us(); sdmmc_t sdmmc; - if (emummc_storage_init_mmc(&emmc_storage, &sdmmc)) { - EPRINTF("Unable to init MMC."); - goto out_wait; - } - TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); - - // Read package1. - u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); - if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { - EPRINTF("Unable to set partition."); - goto out_wait; - } - if (!emummc_storage_read(&emmc_storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { - EPRINTF("Unable to read pkg1."); - goto out_wait; - } - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); - if (!pkg1_id) { - EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); + const pkg1_id_t *pkg1_id; + u8 *pkg1 = _read_pkg1(&sdmmc, &pkg1_id); + if (!pkg1) { goto out_wait; } u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; + bool res = true; if (!h_cfg.t210b01) { tsec_ctxt_t tsec_ctxt; tsec_ctxt.pkg1 = pkg1; - if (!_handle_tsec(&tsec_ctxt, pkg1_id->kb, master_key[KB_FIRMWARE_VERSION_MAX], tsec_keys, sizeof(tsec_keys))) { - free(pkg1); - goto out_wait; - } + res =_derive_tsec_keys(&tsec_ctxt, pkg1_id->kb, &keys); } free(pkg1); + if (res == false) { + goto out_wait; + } // Master key derivation - - // on firmware 6.2.0 only, tsec_query delivers the tsec_root_key - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + AES_128_KEY_SIZE)) { - se_aes_key_set(8, tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) - se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, master_kek[6], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mks) - se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source); + if (h_cfg.t210b01) { + // todo: derive mariko master keys + } else { + _derive_master_keys_post_620_erista(pkg1_id->kb, &keys); + _derive_master_keys_from_keyblobs(&keys); } - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) { - // derive all lower master keys in case keyblobs are bad - if (_key_exists(master_key[pkg1_id->kb])) { - for (u32 i = pkg1_id->kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); - } - se_aes_key_set(8, master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); - if (_key_exists(temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); - memset(master_key, 0, sizeof(master_key)); - } - } else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) { - // handle sept version differences - for (u32 kb = KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { - for (u32 i = kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], master_key_vectors[i]); - } - se_aes_key_set(8, master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); - if (!_key_exists(temp_key)) { - break; - } - memcpy(master_key[kb-1], master_key[kb], AES_128_KEY_SIZE); - memset(master_key[kb], 0, AES_128_KEY_SIZE); - } - if (_key_exists(temp_key)) { - EPRINTF("Unable to derive master keys via sept."); - memset(master_key, 0, sizeof(master_key)); - } - } - } - - u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); - encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; - u8 keyblob_mac[AES_128_KEY_SIZE] = {0}; - u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; - se_aes_key_set(8, tsec_keys, sizeof(tsec_keys) / 2); - se_aes_key_set(9, sbk, sizeof(sbk)); - - if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { - EPRINTF("Unable to read keyblobs."); - } - - for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { - minerva_periodic_training(); - se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) - se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) - se_aes_key_set(7, keyblob_key[i], sizeof(keyblob_key[i])); - se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) - if (i == 0) { - se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, 0, device_key_4x, device_master_key_source_kek_source); - } - - // verify keyblob is not corrupt - se_aes_key_set(10, keyblob_mac_key[i], sizeof(keyblob_mac_key[i])); - se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); - if (memcmp(current_keyblob, keyblob_mac, sizeof(keyblob_mac)) != 0) { - EPRINTFARGS("Keyblob %x corrupt.", i); - continue; - } - - // decrypt keyblobs - se_aes_key_set(6, keyblob_key[i], sizeof(keyblob_key[i])); - se_aes_crypt_ctr(6, &keyblob[i], sizeof(keyblob_t), ¤t_keyblob->key_data, sizeof(keyblob_t), current_keyblob->iv); - - memcpy(package1_key[i], keyblob[i].package1_key, sizeof(package1_key[i])); - memcpy(master_kek[i], keyblob[i].master_kek, sizeof(master_kek[i])); - se_aes_key_set(7, master_kek[i], sizeof(master_kek[i])); - se_aes_crypt_block_ecb(7, 0, master_key[i], master_key_source); - } - free(keyblob_block); - TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); - /* key = unwrap(source, wrapped_key): - key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key - */ - minerva_periodic_training(); - u32 key_generation = fuse_read_odm_keygen_rev(); - if (key_generation) - key_generation--; + _derive_bis_keys(&keys); - if (_key_exists(device_key)) { - if (key_generation) { - _get_device_key(8, temp_key, key_generation, device_key_4x, master_key[0]); - } else - memcpy(temp_key, device_key, AES_128_KEY_SIZE); - se_aes_key_set(8, temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); - // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _generate_kek(8, bis_kek_source, temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10); - memcpy(bis_key[3], bis_key[2], 0x20); - } + TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); + _derive_misc_keys(&keys, &derivable_key_count); - if (_key_exists(master_key[0])) { - _generate_kek(8, header_kek_source, master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, header_key + 0x00, header_key_source + 0x00); - se_aes_crypt_block_ecb(8, 0, header_key + 0x10, header_key_source + 0x10); - } - - if (_key_exists(device_key)) { - _generate_kek(8, save_mac_kek_source, device_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, save_mac_key, save_mac_key_source); - } - - if (_key_exists(master_key[derivable_key_count])) { - derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1; - } - for (u32 i = 0; i < derivable_key_count; i++) { - if (!_key_exists(master_key[i])) - continue; - for (u32 j = 0; j < 3; j++) { - _generate_kek(8, key_area_key_sources[j], master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); - } - se_aes_key_set(8, master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source); - se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); - } - - if (!_key_exists(header_key) || !_key_exists(bis_key[2])) + if (!_key_exists(keys.bis_key[2])) { - EPRINTF("Missing FS keys. Skipping ES/SSL keys."); + EPRINTF("Missing FS keys. Skipping SD seed and titlekeys."); goto key_output; } @@ -561,33 +568,16 @@ void dump_keys() { FIL fp; u32 read_bytes = 0; - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(master_key[0])) { - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(7, eticket_rsa_kekek_source, master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, eticket_rsa_kek_source); - - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(7, ssl_rsa_kek_source_x, master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_rsa_kek_source_y); - } - // Set BIS keys. // PRODINFO/PRODINFOF - se_aes_key_set(0, bis_key[0] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(1, bis_key[0] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(0, keys.bis_key[0] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(1, keys.bis_key[0] + 0x10, AES_128_KEY_SIZE); // SAFE - se_aes_key_set(2, bis_key[1] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(3, bis_key[1] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(2, keys.bis_key[1] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(3, keys.bis_key[1] + 0x10, AES_128_KEY_SIZE); // SYSTEM/USER - se_aes_key_set(4, bis_key[2] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(5, bis_key[2] + 0x10, AES_128_KEY_SIZE); - - // Set header key for NCA decryption. - se_aes_key_set(8, header_key + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(9, header_key + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(4, keys.bis_key[2] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(5, keys.bis_key[2] + 0x10, AES_128_KEY_SIZE); if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { EPRINTF("Unable to set partition."); @@ -622,7 +612,7 @@ void dump_keys() { goto get_titlekeys; } // get sd seed verification vector - if (f_read(&fp, temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { + if (f_read(&fp, keys.temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); goto get_titlekeys; @@ -639,8 +629,8 @@ void dump_keys() { for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; - if (!memcmp(temp_key, read_buf, sizeof(temp_key))) { - memcpy(sd_seed, read_buf + 0x10, sizeof(sd_seed)); + if (!memcmp(keys.temp_key, read_buf, sizeof(keys.temp_key))) { + memcpy(keys.sd_seed, read_buf + 0x10, sizeof(keys.sd_seed)); break; } } @@ -649,7 +639,7 @@ void dump_keys() { TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); get_titlekeys: - if (!_key_exists(eticket_rsa_kek)) + if (!_key_exists(keys.eticket_rsa_kek)) goto dismount; gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); @@ -678,17 +668,17 @@ get_titlekeys: if (keypair_generation) { keypair_generation--; for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; u8 temp_device_key[AES_128_KEY_SIZE] = {0}; - _get_device_key(7, temp_device_key, keypair_generation, device_key_4x, master_key[0]); - _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek_personalized, eticket_rsa_kek_source); - memcpy(temp_key, eticket_rsa_kek_personalized, sizeof(temp_key)); + _get_device_key(7, temp_device_key, keypair_generation, keys.device_key_4x, keys.master_key[0]); + _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys.temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, keys.eticket_rsa_kek_personalized, eticket_rsa_kek_source); + memcpy(keys.temp_key, keys.eticket_rsa_kek_personalized, sizeof(keys.temp_key)); } else { - memcpy(temp_key, eticket_rsa_kek, sizeof(temp_key)); + memcpy(keys.temp_key, keys.eticket_rsa_kek, sizeof(keys.temp_key)); } - se_aes_key_set(6, temp_key, sizeof(temp_key)); + se_aes_key_set(6, keys.temp_key, sizeof(keys.temp_key)); se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), cal0->ext_ecc_rsa2048_eticket_key, sizeof(cal0->ext_ecc_rsa2048_eticket_key), cal0->ext_ecc_rsa2048_eticket_key_iv); // Check public exponent is 65537 big endian @@ -704,8 +694,8 @@ get_titlekeys: se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); - _get_titlekeys_from_save(buf_size, save_mac_key, titlekey_buffer, NULL); - _get_titlekeys_from_save(buf_size, save_mac_key, titlekey_buffer, &rsa_keypair); + _get_titlekeys_from_save(buf_size, keys.save_mac_key, titlekey_buffer, NULL); + _get_titlekeys_from_save(buf_size, keys.save_mac_key, titlekey_buffer, &rsa_keypair); gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); @@ -734,45 +724,45 @@ key_output: ; SAVE_KEY(aes_kek_generation_source); SAVE_KEY(aes_key_generation_source); SAVE_KEY(bis_kek_source); - SAVE_KEY_FAMILY(bis_key, 0); + SAVE_KEY_FAMILY(keys.bis_key, 0); SAVE_KEY_FAMILY(bis_key_source, 0); - SAVE_KEY(device_key); - SAVE_KEY(device_key_4x); - SAVE_KEY(eticket_rsa_kek); - SAVE_KEY(eticket_rsa_kek_personalized); + SAVE_KEY(keys.device_key); + SAVE_KEY(keys.device_key_4x); + SAVE_KEY(keys.eticket_rsa_kek); + SAVE_KEY(keys.eticket_rsa_kek_personalized); SAVE_KEY(eticket_rsa_kek_source); SAVE_KEY(eticket_rsa_kekek_source); SAVE_KEY(header_kek_source); - SAVE_KEY(header_key); + SAVE_KEY(keys.header_key); SAVE_KEY(header_key_source); - SAVE_KEY_FAMILY_VAR(key_area_key_application, key_area_key[0], 0); + SAVE_KEY_FAMILY_VAR(key_area_key_application, keys.key_area_key[0], 0); SAVE_KEY_VAR(key_area_key_application_source, key_area_key_sources[0]); - SAVE_KEY_FAMILY_VAR(key_area_key_ocean, key_area_key[1], 0); + SAVE_KEY_FAMILY_VAR(key_area_key_ocean, keys.key_area_key[1], 0); SAVE_KEY_VAR(key_area_key_ocean_source, key_area_key_sources[1]); - SAVE_KEY_FAMILY_VAR(key_area_key_system, key_area_key[2], 0); + SAVE_KEY_FAMILY_VAR(key_area_key_system, keys.key_area_key[2], 0); SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); - SAVE_KEY_FAMILY(keyblob, 0); - SAVE_KEY_FAMILY(keyblob_key, 0); + SAVE_KEY_FAMILY(keys.keyblob, 0); + SAVE_KEY_FAMILY(keys.keyblob_key, 0); SAVE_KEY_FAMILY(keyblob_key_source, 0); - SAVE_KEY_FAMILY(keyblob_mac_key, 0); + SAVE_KEY_FAMILY(keys.keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); - SAVE_KEY_FAMILY(master_kek, 0); + SAVE_KEY_FAMILY(keys.master_kek, 0); SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); - SAVE_KEY_FAMILY(master_key, 0); + SAVE_KEY_FAMILY(keys.master_key, 0); SAVE_KEY(master_key_source); - SAVE_KEY_FAMILY(package1_key, 0); - SAVE_KEY_FAMILY(package2_key, 0); + SAVE_KEY_FAMILY(keys.package1_key, 0); + SAVE_KEY_FAMILY(keys.package2_key, 0); SAVE_KEY(package2_key_source); SAVE_KEY(per_console_key_source); SAVE_KEY(retail_specific_aes_key_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - SAVE_KEY_VAR(rsa_oaep_kek_generation_source, temp_key); + keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + SAVE_KEY_VAR(rsa_oaep_kek_generation_source, keys.temp_key); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - SAVE_KEY_VAR(rsa_private_kek_generation_source, temp_key); + keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + SAVE_KEY_VAR(rsa_private_kek_generation_source, keys.temp_key); SAVE_KEY(save_mac_kek_source); - SAVE_KEY(save_mac_key); + SAVE_KEY(keys.save_mac_key); SAVE_KEY(save_mac_key_source); SAVE_KEY(save_mac_sd_card_kek_source); SAVE_KEY(save_mac_sd_card_key_source); @@ -780,20 +770,20 @@ key_output: ; SAVE_KEY(sd_card_kek_source); SAVE_KEY(sd_card_nca_key_source); SAVE_KEY(sd_card_save_key_source); - SAVE_KEY(sd_seed); - SAVE_KEY_VAR(secure_boot_key, sbk); - SAVE_KEY(ssl_rsa_kek); + SAVE_KEY(keys.sd_seed); + SAVE_KEY_VAR(secure_boot_key, keys.sbk); + SAVE_KEY(keys.ssl_rsa_kek); SAVE_KEY(ssl_rsa_kek_source_x); SAVE_KEY(ssl_rsa_kek_source_y); - SAVE_KEY_FAMILY(titlekek, 0); + SAVE_KEY_FAMILY(keys.titlekek, 0); SAVE_KEY(titlekek_source); - _save_key("tsec_key", tsec_keys, AES_128_KEY_SIZE, text_buffer); + _save_key("tsec_key", keys.tsec_keys, AES_128_KEY_SIZE, text_buffer); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - _save_key("tsec_root_key", tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); + _save_key("tsec_root_key", keys.tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); - gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); + gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); f_mkdir("sd:/switch"); diff --git a/source/keys/keys.h b/source/keys/keys.h index 4e5d3ba..59284c2 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -19,6 +19,8 @@ #include +#include "../hos/hos.h" + #define AES_128_KEY_SIZE 16 #define RSA_2048_KEY_SIZE 256 @@ -83,6 +85,34 @@ typedef struct { u8 unused[0x150]; } encrypted_keyblob_t; +typedef struct { + u8 temp_key[AES_128_KEY_SIZE], + bis_key[4][AES_128_KEY_SIZE * 2], + device_key[AES_128_KEY_SIZE], + device_key_4x[AES_128_KEY_SIZE], + sd_seed[AES_128_KEY_SIZE], + // FS-related keys + header_key[AES_128_KEY_SIZE * 2], + save_mac_key[AES_128_KEY_SIZE], + // other sysmodule keys + eticket_rsa_kek[AES_128_KEY_SIZE], + eticket_rsa_kek_personalized[AES_128_KEY_SIZE], + ssl_rsa_kek[AES_128_KEY_SIZE], + // keyblob-derived families + keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], + keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], + package1_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], + // master key-derived families + key_area_key[3][KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], + master_kek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], + master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], + package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], + titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], + tsec_keys[AES_128_KEY_SIZE * 2]; + u32 sbk[4]; + keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; +} key_derivation_ctx_t; + #define TPRINTF(text) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", end_time - start_time); \ From e4714995faa6bd331ef11376a58bd98598935f54 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Dec 2020 16:07:58 -0700 Subject: [PATCH 089/166] Bump version to v1.8.5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d303560..ebca3de 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 4 +LPVERSION_BUGFX := 5 ################################################################################ From 044c8b32f0b552899f6769d72a073993c16d40ff Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 7 Dec 2020 19:08:08 -0700 Subject: [PATCH 090/166] nx_savedata: More fail paths, ensure alignment --- .../nx_savedata/allocation_table_storage.c | 13 +++++++-- .../nx_savedata/allocation_table_storage.h | 2 +- ...rarchical_integrity_verification_storage.c | 4 +-- .../hierarchical_save_file_table.c | 4 +-- .../integrity_verification_storage.c | 13 +++++---- bdk/libs/nx_savedata/save.c | 27 ++++++++++--------- bdk/libs/nx_savedata/save_data_file.c | 2 +- .../nx_savedata/save_data_file_system_core.c | 18 +++++++++---- .../nx_savedata/save_data_file_system_core.h | 2 +- 9 files changed, 51 insertions(+), 34 deletions(-) diff --git a/bdk/libs/nx_savedata/allocation_table_storage.c b/bdk/libs/nx_savedata/allocation_table_storage.c index 43cea04..97b2dfb 100644 --- a/bdk/libs/nx_savedata/allocation_table_storage.c +++ b/bdk/libs/nx_savedata/allocation_table_storage.c @@ -38,12 +38,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) { +bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) { ctx->base_storage = data; ctx->block_size = block_size; ctx->fat = table; ctx->initial_block = initial_block; - ctx->_length = initial_block == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(table, initial_block) * block_size; + ctx->_length = 0; + if (initial_block != 0xFFFFFFFF) { + uint32_t list_length = save_allocation_table_get_list_length(table, initial_block); + if (list_length == 0) { + EPRINTF("Allocation table storage init failed!"); + return false; + }; + ctx->_length = list_length * block_size; + } + return true; } uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { diff --git a/bdk/libs/nx_savedata/allocation_table_storage.h b/bdk/libs/nx_savedata/allocation_table_storage.h index 86f55cf..6e8d30c 100644 --- a/bdk/libs/nx_savedata/allocation_table_storage.h +++ b/bdk/libs/nx_savedata/allocation_table_storage.h @@ -52,7 +52,7 @@ static ALWAYS_INLINE void save_allocation_table_storage_get_size(allocation_tabl *out_size = ctx->_length; } -void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block); +bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block); uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size); diff --git a/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c index 4d8153b..d244571 100644 --- a/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c +++ b/bdk/libs/nx_savedata/hierarchical_integrity_verification_storage.c @@ -135,7 +135,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica validity_t result = VALIDITY_VALID; integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[3]; - uint64_t block_size = storage->base_storage.sector_size; + uint32_t block_size = storage->base_storage.sector_size; uint32_t block_count = (uint32_t)(DIV_ROUND_UP(ctx->length, block_size)); uint8_t *buffer = malloc(block_size); @@ -143,7 +143,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica for (unsigned int i = 0; i < block_count; i++) { if (ctx->level_validities[3][i] == VALIDITY_UNCHECKED) { uint64_t storage_size = storage->base_storage.length; - uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), (uint32_t)block_size); + uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), block_size); substorage_read(&ctx->data_level->base_storage, buffer, block_size * i, to_read); } if (ctx->level_validities[3][i] == VALIDITY_INVALID) { diff --git a/bdk/libs/nx_savedata/hierarchical_save_file_table.c b/bdk/libs/nx_savedata/hierarchical_save_file_table.c index 0ae9126..0aae473 100644 --- a/bdk/libs/nx_savedata/hierarchical_save_file_table.c +++ b/bdk/libs/nx_savedata/hierarchical_save_file_table.c @@ -207,7 +207,7 @@ void save_hierarchical_file_table_unlink_file_from_parent(hierarchical_save_file return; } prev_index = cur_index; - memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); + memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t)); cur_index = prev_entry.next_sibling; } } @@ -236,7 +236,7 @@ void save_hierarchical_file_table_unlink_directory_from_parent(hierarchical_save return; } prev_index = cur_index; - memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); + memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t)); cur_index = prev_entry.next_sibling; } } diff --git a/bdk/libs/nx_savedata/integrity_verification_storage.c b/bdk/libs/nx_savedata/integrity_verification_storage.c index fc76501..3e5bba7 100644 --- a/bdk/libs/nx_savedata/integrity_verification_storage.c +++ b/bdk/libs/nx_savedata/integrity_verification_storage.c @@ -52,7 +52,7 @@ void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity /* buffer must have size count + 0x20 for salt to by copied in at offset 0. */ static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) { memcpy(buffer, ctx->salt, sizeof(ctx->salt)); - se_calc_sha256(out_hash, buffer, count + sizeof(ctx->salt)); + se_calc_sha256_oneshot(out_hash, buffer, count + sizeof(ctx->salt)); out_hash[0x1F] |= 0x80; } @@ -81,7 +81,7 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf return false; } - uint8_t hash_buffer[0x20] = {0}; + uint8_t hash_buffer[0x20] __attribute__((aligned(4))) = {0}; uint64_t hash_pos = block_index * sizeof(hash_buffer); if (substorage_read(&ctx->hash_storage, hash_buffer, hash_pos, sizeof(hash_buffer)) != sizeof(hash_buffer)) @@ -99,17 +99,16 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf return false; } + memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count); + if (ctx->integrity_check_level && ctx->block_validities[block_index] != VALIDITY_UNCHECKED) { - memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count); free(data_buffer); return true; } - uint8_t hash[0x20] = {0}; + uint8_t hash[0x20] __attribute__((aligned(4))) = {0}; save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size); - memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count); free(data_buffer); - if (memcmp(hash_buffer, hash, sizeof(hash_buffer)) == 0) { ctx->block_validities[block_index] = VALIDITY_VALID; } else { @@ -127,7 +126,7 @@ bool save_ivfc_storage_write(integrity_verification_storage_ctx_t *ctx, const vo uint64_t block_index = offset / ctx->base_storage.sector_size; uint64_t hash_pos = block_index * 0x20; - uint8_t hash[0x20] = {0}; + uint8_t hash[0x20] __attribute__((aligned(4))) = {0}; uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20); if (count < ctx->base_storage.sector_size) { if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) { diff --git a/bdk/libs/nx_savedata/save.c b/bdk/libs/nx_savedata/save.c index 7669e10..979c948 100644 --- a/bdk/libs/nx_savedata/save.c +++ b/bdk/libs/nx_savedata/save.c @@ -98,13 +98,13 @@ static bool save_process_header(save_ctx_t *ctx) { ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; - uint8_t hash[0x20]; + uint8_t hash[0x20] __attribute__((aligned(4))); uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; - se_calc_sha256(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size); - ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; + se_calc_sha256_oneshot(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size); + ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, sizeof(hash)) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; - unsigned char cmac[0x10] = {}; + uint8_t cmac[0x10] __attribute__((aligned(4))); se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { @@ -126,14 +126,14 @@ bool save_process(save_ctx_t *ctx) { substorage_init(&ctx->base_storage, &file_storage_vt, ctx->file, 0, f_size(ctx->file)); /* Try to parse Header A. */ if (substorage_read(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) { - EPRINTF("Failed to read save header!\n"); + EPRINTF("Failed to read save header A!\n"); return false; } if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { /* Try to parse Header B. */ if (substorage_read(&ctx->base_storage, &ctx->header, sizeof(ctx->header), sizeof(ctx->header)) != sizeof(ctx->header)) { - EPRINTF("Failed to read save header!\n"); + EPRINTF("Failed to read save header B!\n"); return false; } @@ -147,10 +147,13 @@ bool save_process(save_ctx_t *ctx) { ctx->data_remap_storage.header = &ctx->header.main_remap_header; ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; + u32 data_remap_entry_size = sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count; + u32 meta_remap_entry_size = sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count; + substorage_init(&ctx->data_remap_storage.base_storage, &file_storage_vt, ctx->file, ctx->header.layout.file_map_data_offset, ctx->header.layout.file_map_data_size); ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); - uint8_t *remap_buffer = malloc(MAX(ctx->data_remap_storage.header->map_entry_count, ctx->meta_remap_storage.header->map_entry_count) * sizeof(remap_entry_t)); - if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) { + uint8_t *remap_buffer = malloc(MAX(data_remap_entry_size, meta_remap_entry_size)); + if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, data_remap_entry_size) != data_remap_entry_size) { EPRINTF("Failed to read data remap table!"); free(remap_buffer); return false; @@ -177,7 +180,7 @@ bool save_process(save_ctx_t *ctx) { /* Initialize meta remap storage. */ substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length); ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); - if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) { + if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, meta_remap_entry_size) != meta_remap_entry_size) { EPRINTF("Failed to read meta remap table!"); free(remap_buffer); return false; @@ -225,9 +228,7 @@ bool save_process(save_ctx_t *ctx) { } /* Initialize core save filesystem. */ - save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header); - - return true; + return save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header); } void save_free_contexts(save_ctx_t *ctx) { @@ -292,7 +293,7 @@ bool save_commit(save_ctx_t *ctx) { uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; uint8_t *header = (uint8_t *)&ctx->header; - se_calc_sha256(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size); + se_calc_sha256_oneshot(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size); se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); diff --git a/bdk/libs/nx_savedata/save_data_file.c b/bdk/libs/nx_savedata/save_data_file.c index 0940052..edf85ba 100644 --- a/bdk/libs/nx_savedata/save_data_file.c +++ b/bdk/libs/nx_savedata/save_data_file.c @@ -38,7 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode) { ctx->mode = mode; - memcpy(&ctx->base_storage, base_storage, sizeof(ctx->base_storage)); + memcpy(&ctx->base_storage, base_storage, sizeof(allocation_table_storage_ctx_t)); ctx->path = path; ctx->file_table = file_table; ctx->size = size; diff --git a/bdk/libs/nx_savedata/save_data_file_system_core.c b/bdk/libs/nx_savedata/save_data_file_system_core.c index ccd3a2c..03275cb 100644 --- a/bdk/libs/nx_savedata/save_data_file_system_core.c +++ b/bdk/libs/nx_savedata/save_data_file_system_core.c @@ -41,21 +41,29 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static ALWAYS_INLINE void save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { - save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index); +static ALWAYS_INLINE bool save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { + return save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index); } -void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) { +bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) { save_allocation_table_init(&ctx->allocation_table, allocation_table, &save_fs_header->fat_header); ctx->header = save_fs_header; ctx->base_storage = storage; save_filesystem_list_ctx_t *dir_table = &ctx->file_table.directory_table; save_filesystem_list_ctx_t *file_table = &ctx->file_table.file_table; - save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block); - save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block); + if (!save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block)) { + EPRINTF("Failed to init dir table for fs core!"); + return false; + } + if (!save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block)) { + EPRINTF("Failed to init file table for fs core!"); + return false; + } save_fs_list_init(dir_table); save_fs_list_init(file_table); + + return true; } bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path) { diff --git a/bdk/libs/nx_savedata/save_data_file_system_core.h b/bdk/libs/nx_savedata/save_data_file_system_core.h index 14c4523..3c69cde 100644 --- a/bdk/libs/nx_savedata/save_data_file_system_core.h +++ b/bdk/libs/nx_savedata/save_data_file_system_core.h @@ -66,7 +66,7 @@ static ALWAYS_INLINE void save_data_file_system_core_get_total_space_size(save_d *out_total_space = ctx->header->block_size * ctx->header->block_count; } -void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header); +bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header); bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path); bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size); From a0eaa5e4edc4ef317f2daa5724a55f6769529545 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 7 Dec 2020 19:11:33 -0700 Subject: [PATCH 091/166] Support Mariko, patched Erista --- bdk/sec/se.c | 314 +++++++++++++++++++++++++++--------- bdk/sec/se.h | 10 +- bdk/sec/se_t210.h | 4 + bdk/soc/pmc.h | 4 + source/hos/pkg1.h | 13 ++ source/keys/key_sources.inl | 70 ++++---- source/keys/keys.c | 142 +++++++++------- source/main.c | 32 +++- 8 files changed, 406 insertions(+), 183 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 7be46c9..de7fb9b 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -93,22 +94,21 @@ static int _se_wait() return 1; } -static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +se_ll_t *ll_dst, *ll_src; +static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot) { - static se_ll_t *ll_dst = NULL, *ll_src = NULL; - if (!ll_dst) - { - ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); - ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); - } + ll_dst = NULL; + ll_src = NULL; if (dst) { + ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_dst, (u32)dst, dst_size); } if (src) { + ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_src, (u32)src, src_size); } @@ -120,13 +120,49 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + + if (is_oneshot) + { + int res = _se_wait(); + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + if (src) + free(ll_src); + if (dst) + free(ll_dst); + + return res; + } + + return 1; +} + +static int _se_execute_finalize() +{ int res = _se_wait(); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + if (ll_src) + { + free(ll_src); + ll_src = NULL; + } + if (ll_dst) + { + free(ll_dst); + ll_dst = NULL; + } + return res; } +static int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + return _se_execute(op, dst, dst_size, src, src_size, true); +} + static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) { if (!src || !dst) @@ -138,7 +174,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; memcpy(block, src, src_size); - int res = _se_execute(op, block, 0x10, block, 0x10); + int res = _se_execute_oneshot(op, block, 0x10, block, 0x10); memcpy(dst, block, dst_size); free(block); @@ -147,9 +183,11 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr static void _se_aes_ctr_set(void *ctr) { - u32 *data = (u32 *)ctr; - for (u32 i = 0; i < 4; i++) - SE(SE_CRYPTO_CTR_REG_OFFSET + 4 * i) = data[i]; + u32 data[TEGRA_SE_AES_BLOCK_SIZE / 4]; + memcpy(data, ctr, TEGRA_SE_AES_BLOCK_SIZE); + + for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) + SE(SE_CRYPTO_CTR_REG_OFFSET + (4 * i)) = data[i]; } void se_rsa_acc_ctrl(u32 rs, u32 flags) @@ -159,7 +197,7 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags) ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); + SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~BIT(rs); } // se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot @@ -212,7 +250,7 @@ int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_siz SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1; SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2; - res = _se_execute(OP_START, NULL, 0, stack_buf, src_size); + res = _se_execute_oneshot(OP_START, NULL, 0, stack_buf, src_size); // Copy output hash. u32 *dst32 = (u32 *)dst; @@ -227,7 +265,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags) if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); + SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~BIT(ks); } u32 se_key_acc_ctrl_get(u32 ks) @@ -237,48 +275,55 @@ u32 se_key_acc_ctrl_get(u32 ks) void se_aes_key_set(u32 ks, const void *key, u32 size) { - u32 *data = (u32 *)key; - for (u32 i = 0; i < size / 4; i++) + u32 data[TEGRA_SE_AES_MAX_KEY_SIZE / 4]; + memcpy(data, key, size); + + for (u32 i = 0; i < (size / 4); i++) { SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; } } -void se_aes_iv_set(u32 ks, const void *iv, u32 size) +void se_aes_iv_set(u32 ks, const void *iv) { - u32 *data = (u32 *)iv; - for (u32 i = 0; i < size / 4; i++) + u32 data[TEGRA_SE_AES_BLOCK_SIZE / 4]; + memcpy(data, iv, TEGRA_SE_AES_BLOCK_SIZE); + + for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i; + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(QUAD_ORG_IV) | i; SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; } } -void se_aes_key_read(u32 ks, void *key, u32 size) +void se_aes_key_get(u32 ks, void *key, u32 size) { - u32 *data = (u32 *)key; - for (u32 i = 0; i < size / 4; i++) + u32 data[TEGRA_SE_AES_MAX_KEY_SIZE / 4]; + + for (u32 i = 0; i < (size / 4); i++) { SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; data[i] = SE(SE_KEYTABLE_DATA0_REG_OFFSET); } + + memcpy(key, data, size); } void se_aes_key_clear(u32 ks) { - for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++) + for (u32 i = 0; i < (TEGRA_SE_AES_MAX_KEY_SIZE / 4); i++) { SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; } } -void se_aes_key_iv_clear(u32 ks) +void se_aes_iv_clear(u32 ks) { - for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++) + for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i; + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(QUAD_ORG_IV) | i; SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; } } @@ -290,7 +335,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); - return _se_execute(OP_START, NULL, 0, input, 0x10); + return _se_execute_oneshot(OP_START, NULL, 0, input, 0x10); } int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) @@ -306,7 +351,25 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); } SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - return _se_execute(OP_START, dst, dst_size, src, src_size); + return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP); + } + else + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) | + SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM); + } + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); } int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) @@ -319,8 +382,7 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s SE(SE_SPARE_0_REG_OFFSET) = 1; SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) | - SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB); + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); _se_aes_ctr_set(ctr); u32 src_size_aligned = src_size & 0xFFFFFFF0; @@ -329,7 +391,7 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s if (src_size_aligned) { SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - if (!_se_execute(OP_START, dst, dst_size, src, src_size_aligned)) + if (!_se_execute_oneshot(OP_START, dst, dst_size, src, src_size_aligned)) return 0; } @@ -359,7 +421,7 @@ int se_initialize_rng() SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0); + int res =_se_execute_oneshot(OP_START, output_buf, 0x10, NULL, 0); free(output_buf); if (res) @@ -378,7 +440,7 @@ int se_generate_random(void *dst, u32 size) if (num_blocks) { SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 1; - if (!_se_execute(OP_START, dst, aligned_size, NULL, 0)) + if (!_se_execute_oneshot(OP_START, dst, aligned_size, NULL, 0)) return 0; } if (size > aligned_size) @@ -394,35 +456,15 @@ int se_generate_random_key(u32 ks_dst, u32 ks_src) SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); - if (!_se_execute(OP_START, NULL, 0, NULL, 0)) + if (!_se_execute_oneshot(OP_START, NULL, 0, NULL, 0)) return 0; SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1; - if (!_se_execute(OP_START, NULL, 0, NULL, 0)) + if (!_se_execute_oneshot(OP_START, NULL, 0, NULL, 0)) return 0; return 1; } -int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) -{ - if (enc) - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | - SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | - SE_CRYPTO_IV_SEL(IV_ORIGINAL); - } - else - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) | - SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | - SE_CRYPTO_IV_SEL(IV_ORIGINAL); - } - SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - return _se_execute(OP_START, dst, dst_size, src, src_size); -} - int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size) { u8 tweak[0x10]; @@ -500,13 +542,13 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); - se_aes_key_iv_clear(ks); + se_aes_iv_clear(ks); u32 num_blocks = (src_size + 0xf) >> 4; if (num_blocks > 1) { SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2; - if (!_se_execute(OP_START, NULL, 0, src, src_size)) + if (!_se_execute_oneshot(OP_START, NULL, 0, src, src_size)) goto out; SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED); } @@ -525,7 +567,7 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) last_block[i] ^= key[i]; SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - res = _se_execute(OP_START, NULL, 0, last_block, 0x10); + res = _se_execute_oneshot(OP_START, NULL, 0, last_block, 0x10); u32 *dst32 = (u32 *)dst; for (u32 i = 0; i < (dst_size >> 2); i++) @@ -537,29 +579,91 @@ out:; return res; } -// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256. -int se_calc_sha256(void *dst, const void *src, u32 src_size) +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) { int res; - // Setup config for SHA256, size = BITS(src_size). + u32 hash32[TEGRA_SE_SHA_256_SIZE / 4]; + + //! TODO: src_size must be 512 bit aligned if continuing and not last block for SHA256. + if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. + return 0; + + // Setup config for SHA256. SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH; - SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0; + SE(SE_SHA_CONFIG_REG_OFFSET) = sha_cfg; + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + + // Set total size to current buffer size if empty. + if (!total_size) + total_size = src_size; + + // Set total size: BITS(src_size), up to 2 EB. + SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = (u32)(total_size >> 29); SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0; + + // Set size left to hash. + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = (u32)(total_size >> 29); SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; + // If we hash in chunks, copy over the intermediate. + if (sha_cfg == SHA_CONTINUE && msg_left) + { + // Restore message left to process. + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = msg_left[0]; + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = msg_left[1]; + + // Restore hash reg. + memcpy(hash32, hash, TEGRA_SE_SHA_256_SIZE); + for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) + SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)) = byte_swap_32(hash32[i]); + } + // Trigger the operation. - res = _se_execute(OP_START, NULL, 0, src, src_size); + res = _se_execute(OP_START, NULL, 0, src, src_size, is_oneshot); + + if (is_oneshot) + { + // Backup message left. + if (msg_left) + { + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + } + + // Copy output hash. + for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); + memcpy(hash, hash32, TEGRA_SE_SHA_256_SIZE); + } + + return res; +} + +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size) +{ + return se_calc_sha256(hash, NULL, src, src_size, 0, SHA_INIT_HASH, true); +} + +int se_calc_sha256_finalize(void *hash, u32 *msg_left) +{ + u32 hash32[TEGRA_SE_SHA_256_SIZE / 4]; + int res = _se_execute_finalize(); + + // Backup message left. + if (msg_left) + { + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + } // Copy output hash. - u32 *dst32 = (u32 *)dst; - for (u32 i = 0; i < 8; i++) - dst32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); + for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); + memcpy(hash, hash32, TEGRA_SE_SHA_256_SIZE); return res; } @@ -573,7 +677,7 @@ int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *ke if (key_size > 0x40) { - if (!se_calc_sha256(secret, key, key_size)) + if (!se_calc_sha256_oneshot(secret, key, key_size)) goto out; memset(secret + 0x20, 0, 0x20); } @@ -593,10 +697,10 @@ int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *ke } memcpy(ipad + 0x40, src, src_size); - if (!se_calc_sha256(dst, ipad, 0x40 + src_size)) + if (!se_calc_sha256_oneshot(dst, ipad, 0x40 + src_size)) goto out; memcpy(opad + 0x40, dst, 0x20); - if (!se_calc_sha256(dst, opad, 0x60)) + if (!se_calc_sha256_oneshot(dst, opad, 0x60)) goto out; res = 1; @@ -611,8 +715,8 @@ out:; // _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { - u8 cur_hash[0x20]; - u8 hash_buf[0xe4]; + u8 cur_hash[0x20] __attribute__((aligned(4))); + u8 hash_buf[0xe4] __attribute__((aligned(4))); u32 hash_buf_size = seed_size + 4; memcpy(hash_buf, seed, seed_size); @@ -627,7 +731,7 @@ static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_ hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; round_num++; - se_calc_sha256(cur_hash, hash_buf, hash_buf_size); + se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size); for (unsigned int i = 0; i < cur_size; i++) { *p_out ^= cur_hash[i]; @@ -678,3 +782,59 @@ u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 la return msg_size; } +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) +{ + u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40); + + // Set Secure Random Key. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_START, NULL, 0, NULL, 0); + + // Save AES keys. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + + for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | + (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); + memcpy(keys + i * keysize, aligned_buf, 0x10); + + if (keysize > 0x10) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | + (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); + memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10); + } + } + + // Save SRK to PMC secure scratches. + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + + // End context save. + SE(SE_CONFIG_REG_OFFSET) = 0; + _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + + // Get SRK. + u32 srk[4]; + srk[0] = PMC(APBDEV_PMC_SECURE_SCRATCH4); + srk[1] = PMC(APBDEV_PMC_SECURE_SCRATCH5); + srk[2] = PMC(APBDEV_PMC_SECURE_SCRATCH6); + srk[3] = PMC(APBDEV_PMC_SECURE_SCRATCH7); + + // Decrypt context. + se_aes_key_clear(3); + se_aes_key_set(3, srk, 0x10); + se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize); + se_aes_key_clear(3); +} diff --git a/bdk/sec/se.h b/bdk/sec/se.h index f10acb3..9126d7f 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -26,9 +26,10 @@ int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_siz void se_key_acc_ctrl(u32 ks, u32 flags); u32 se_key_acc_ctrl_get(u32 ks); void se_aes_key_set(u32 ks, const void *key, u32 size); -void se_aes_iv_set(u32 ks, const void *iv, u32 size); -void se_aes_key_read(u32 ks, void *key, u32 size); +void se_aes_iv_set(u32 ks, const void *iv); +void se_aes_key_get(u32 ks, void *key, u32 size); void se_aes_key_clear(u32 ks); +void se_aes_iv_clear(u32 ks); int se_initialize_rng(); int se_generate_random(void *dst, u32 size); int se_generate_random_key(u32 ks_dst, u32 ks_src); @@ -40,8 +41,11 @@ int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size); int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); -int se_calc_sha256(void *dst, const void *src, u32 src_size); +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot); +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); +int se_calc_sha256_finalize(void *hash, u32 *msg_left); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); #endif diff --git a/bdk/sec/se_t210.h b/bdk/sec/se_t210.h index 0169869..6fbf1b0 100644 --- a/bdk/sec/se_t210.h +++ b/bdk/sec/se_t210.h @@ -265,6 +265,10 @@ #define TEGRA_SE_AES_MIN_KEY_SIZE 16 #define TEGRA_SE_AES_MAX_KEY_SIZE 32 #define TEGRA_SE_AES_IV_SIZE 16 +#define TEGRA_SE_SHA_512_SIZE 64 +#define TEGRA_SE_SHA_384_SIZE 48 +#define TEGRA_SE_SHA_256_SIZE 32 +#define TEGRA_SE_SHA_192_SIZE 24 #define TEGRA_SE_RNG_IV_SIZE 16 #define TEGRA_SE_RNG_DT_SIZE 16 #define TEGRA_SE_RNG_KEY_SIZE 16 diff --git a/bdk/soc/pmc.h b/bdk/soc/pmc.h index 45fa034..c27d937 100644 --- a/bdk/soc/pmc.h +++ b/bdk/soc/pmc.h @@ -40,6 +40,8 @@ #define PMC_SCRATCH0_MODE_CUSTOM_ALL (PMC_SCRATCH0_MODE_RECOVERY | PMC_SCRATCH0_MODE_FASTBOOT | PMC_SCRATCH0_MODE_PAYLOAD) #define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 +#define APBDEV_PMC_SECURE_SCRATCH4 0xC0 +#define APBDEV_PMC_SECURE_SCRATCH5 0xC4 #define APBDEV_PMC_PWR_DET_VAL 0xE4 #define PMC_PWR_DET_SDMMC1_IO_EN BIT(12) #define PMC_PWR_DET_AUDIO_HV BIT(18) @@ -63,6 +65,8 @@ #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 #define APBDEV_PMC_VDDP_SEL 0x1CC #define APBDEV_PMC_DDR_CFG 0x1D0 +#define APBDEV_PMC_SECURE_SCRATCH6 0x224 +#define APBDEV_PMC_SECURE_SCRATCH7 0x228 #define APBDEV_PMC_SCRATCH45 0x234 #define APBDEV_PMC_SCRATCH46 0x238 #define APBDEV_PMC_SCRATCH49 0x244 diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index da1df35..81bef20 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -23,6 +23,19 @@ #define PKG1_OFFSET 0x100000 #define KEYBLOB_OFFSET 0x180000 +typedef struct _bl_hdr_t210b01_t +{ + u8 aes_mac[0x10]; + u8 rsa_sig[0x100]; + u8 salt[0x20]; + u8 sha256[0x20]; + u32 version; + u32 size; + u32 load_addr; + u32 entrypoint; + u8 rsvd[0x10]; +} bl_hdr_t210b01_t; + typedef struct _pkg1_id_t { const char *id; diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 8a23b96..0ba95f9 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -15,11 +15,11 @@ */ // Sha256 hash of the null string. -static u8 null_hash[0x20] = { +static const u8 null_hash[0x20] __attribute__((aligned(4))) = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; -static const u8 keyblob_key_source[][0x10] = { +static const u8 keyblob_key_source[][0x10] __attribute__((aligned(4))) = { {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 @@ -28,7 +28,7 @@ static const u8 keyblob_key_source[][0x10] = { {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 }; -static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] = { +static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] __attribute__((aligned(4))) = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 @@ -36,7 +36,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 }; -static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] = { +static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ @@ -52,29 +52,29 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] = { //======================================Keys======================================// // from Package1 -> Secure_Monitor -static const u8 aes_kek_generation_source[0x10] = { +static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_kek_seed_01[0x10] = { +static const u8 aes_kek_seed_01[0x10] __attribute__((aligned(4))) = { 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_kek_seed_03[0x10] = { +static const u8 aes_kek_seed_03[0x10] __attribute__((aligned(4))) = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; -static const u8 package2_key_source[0x10] = { +static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; -static const u8 titlekek_source[0x10] = { +static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -static const u8 retail_specific_aes_key_source[0x10] = { +static const u8 retail_specific_aes_key_source[0x10] __attribute__((aligned(4))) = { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; // from Package1ldr (or Secure_Monitor on 6.2.0+) -static const u8 keyblob_mac_key_source[0x10] = { +static const u8 keyblob_mac_key_source[0x10] __attribute__((aligned(4))) = { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; -static const u8 master_key_source[0x10] = { +static const u8 master_key_source[0x10] __attribute__((aligned(4))) = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; -static const u8 per_console_key_source[0x10] = { +static const u8 per_console_key_source[0x10] __attribute__((aligned(4))) = { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; -static const u8 device_master_key_source_kek_source[0x10] = { +static const u8 device_master_key_source_kek_source[0x10] __attribute__((aligned(4))) = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; -static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] = { +static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56}, // 6.0.0. {0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE}, // 6.2.0. {0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A}, // 7.0.0. @@ -83,7 +83,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. }; -static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { +static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ @@ -95,18 +95,18 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI }; // from ES -static const u8 eticket_rsa_kek_source[0x10] = { +static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; -static const u8 eticket_rsa_kekek_source[0x10] = { +static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; // from SSL -static const u8 ssl_rsa_kek_source_x[0x10] = { +static const u8 ssl_rsa_kek_source_x[0x10] __attribute__((aligned(4))) = { 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; -static const u8 ssl_rsa_kek_source_y[0x10] = { +static const u8 ssl_rsa_kek_source_y[0x10] __attribute__((aligned(4))) = { 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; -static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { +static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ @@ -118,13 +118,13 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ }; // from SPL -static const u8 aes_key_generation_source[0x10] = { +static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; // from FS -static const u8 bis_kek_source[0x10] = { +static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] = { +static const u8 bis_key_source[3][0x20] __attribute__((aligned(4))) = { {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, @@ -132,32 +132,32 @@ static const u8 bis_key_source[3][0x20] = { {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} }; -static const u8 header_kek_source[0x10] = { +static const u8 header_kek_source[0x10] __attribute__((aligned(4))) = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}; -static const u8 header_key_source[0x20] = { +static const u8 header_key_source[0x20] __attribute__((aligned(4))) = { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}; -static const u8 key_area_key_sources[3][0x10] = { +static const u8 key_area_key_sources[3][0x10] __attribute__((aligned(4))) = { {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system }; -static const u8 save_mac_kek_source[0x10] = { +static const u8 save_mac_kek_source[0x10] __attribute__((aligned(4))) = { 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; -static const u8 save_mac_key_source[0x10] = { +static const u8 save_mac_key_source[0x10] __attribute__((aligned(4))) = { 0XE4, 0XCD, 0X3D, 0X4A, 0XD5, 0X0F, 0X74, 0X28, 0X45, 0XA4, 0X87, 0XE5, 0XA0, 0X63, 0XEA, 0X1F}; -static const u8 save_mac_sd_card_kek_source[0x10] = { +static const u8 save_mac_sd_card_kek_source[0x10] __attribute__((aligned(4))) = { 0X04, 0X89, 0XEF, 0X5D, 0X32, 0X6E, 0X1A, 0X59, 0XC4, 0XB7, 0XAB, 0X8C, 0X36, 0X7A, 0XAB, 0X17}; -static const u8 save_mac_sd_card_key_source[0x10] = { +static const u8 save_mac_sd_card_key_source[0x10] __attribute__((aligned(4))) = { 0X6F, 0X64, 0X59, 0X47, 0XC5, 0X61, 0X46, 0XF9, 0XFF, 0XA0, 0X45, 0XD5, 0X95, 0X33, 0X29, 0X18}; -static const u8 sd_card_custom_storage_key_source[0x20] = { +static const u8 sd_card_custom_storage_key_source[0x20] __attribute__((aligned(4))) = { 0X37, 0X0C, 0X34, 0X5E, 0X12, 0XE4, 0XCE, 0XFE, 0X21, 0XB5, 0X8E, 0X64, 0XDB, 0X52, 0XAF, 0X35, 0X4F, 0X2C, 0XA5, 0XA3, 0XFC, 0X99, 0X9A, 0X47, 0XC0, 0X3E, 0XE0, 0X04, 0X48, 0X5B, 0X2F, 0XD0}; -static const u8 sd_card_kek_source[0x10] = { +static const u8 sd_card_kek_source[0x10] __attribute__((aligned(4))) = { 0X88, 0X35, 0X8D, 0X9C, 0X62, 0X9B, 0XA1, 0XA0, 0X01, 0X47, 0XDB, 0XE0, 0X62, 0X1B, 0X54, 0X32}; -static const u8 sd_card_nca_key_source[0x20] = { +static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = { 0X58, 0X41, 0XA2, 0X84, 0X93, 0X5B, 0X56, 0X27, 0X8B, 0X8E, 0X1F, 0XC5, 0X18, 0XE9, 0X9F, 0X2B, 0X67, 0XC7, 0X93, 0XF0, 0XF2, 0X4F, 0XDE, 0XD0, 0X75, 0X49, 0X5D, 0XCA, 0X00, 0X6D, 0X99, 0XC2}; -static const u8 sd_card_save_key_source[0x20] = { +static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = { 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 5f83a57..fa850bc 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -74,7 +74,7 @@ static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); -static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key); +static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *new_device_key, const void *master_key); // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); @@ -112,9 +112,12 @@ static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { EPRINTF("Unable to read pkg1."); return NULL; } - *pkg1_id = pkg1_identify(pkg1); + + u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. + *pkg1_id = pkg1_identify(pkg1 + pk1_offset); if (!*pkg1_id) { EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); + gfx_hexdump(0, pkg1, 0x20); return NULL; } @@ -169,7 +172,7 @@ static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { return false; } } else { - se_aes_key_read(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, out_key, AES_128_KEY_SIZE); + se_aes_key_get(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, out_key, AES_128_KEY_SIZE); } return true; @@ -225,8 +228,15 @@ static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx return true; } -static void _derive_master_keys_post_620_erista(u32 pkg1_kb, key_derivation_ctx_t *keys) { - u8 temp_key[AES_128_KEY_SIZE]; +static void _derive_master_key_mariko(u32 kb, key_derivation_ctx_t *keys) { + // Relies on the SBK being properly set in slot 14 + se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); + // Relies on the Mariko KEK being properly set in slot 12 + se_aes_unwrap_key(8, 12, &mariko_master_kek_sources[kb - KB_FIRMWARE_VERSION_600]); + se_aes_crypt_block_ecb(8, 0, keys->master_key[kb], master_key_source); +} + +static void _derive_master_keys_post_620(u32 pkg1_kb, key_derivation_ctx_t *keys) { // on firmware 6.2.0 only, the tsec_root_key is available if (pkg1_kb == KB_FIRMWARE_VERSION_620 && _key_exists(keys->tsec_keys + AES_128_KEY_SIZE)) { se_aes_key_set(8, keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) @@ -244,15 +254,15 @@ static void _derive_master_keys_post_620_erista(u32 pkg1_kb, key_derivation_ctx_ se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); } se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, temp_key, master_key_vectors[0]); - if (!_key_exists(temp_key)) { + se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); + if (!_key_exists(keys->temp_key)) { break; } memcpy(keys->master_key[kb - 1], keys->master_key[kb], AES_128_KEY_SIZE); memset(keys->master_key[kb], 0, AES_128_KEY_SIZE); } - if (_key_exists(temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_kb); + if (_key_exists(keys->temp_key)) { + EPRINTFARGS("Unable to derive master key. kb = %d.\n Check sept files on SD and retry.", pkg1_kb); memset(keys->master_key, 0, sizeof(keys->master_key)); } } @@ -261,11 +271,20 @@ static void _derive_master_keys_post_620_erista(u32 pkg1_kb, key_derivation_ctx_ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; - u8 keyblob_mac[AES_128_KEY_SIZE] = {0}; + u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; + keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); keys->sbk[1] = FUSE(FUSE_PRIVATE_KEY1); keys->sbk[2] = FUSE(FUSE_PRIVATE_KEY2); keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); + + if (keys->sbk[0] == 0xFFFFFFFF) { + u8 *aes_keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); + memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + free(aes_keys); + } + se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); se_aes_key_set(9, keys->sbk, sizeof(keys->sbk)); @@ -315,23 +334,21 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { if (key_generation) key_generation--; - if (_key_exists(keys->device_key)) { - if (key_generation) { - _get_device_key(8, keys->temp_key, key_generation, keys->device_key_4x, keys->master_key[0]); - } else - memcpy(keys->temp_key, keys->device_key, AES_128_KEY_SIZE); - se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_source[0] + 0x10); - // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_source[2] + 0x10); - memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); + if (!(_key_exists(keys->device_key) || (key_generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { + return; } + _get_device_key(8, keys->temp_key, key_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); + se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); + se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_source[0] + 0x10); + // kek = generate_kek(bkeks, devkey, aeskek, aeskey) + _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_source[1] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_source[2] + 0x00); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_source[2] + 0x10); + memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); } static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_count) { @@ -365,13 +382,13 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_cou if (_key_exists(keys->master_key[0])) { for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(7, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek, eticket_rsa_kek_source); + _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(8, 0, keys->eticket_rsa_kek, eticket_rsa_kek_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(7, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); + _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(8, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); } } @@ -411,8 +428,8 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } - char ticket_bin_path[0x40] = "/ticket.bin"; - char ticket_list_bin_path[0x40] = "/ticket_list.bin"; + char ticket_bin_path[32] = "/ticket.bin"; + char ticket_list_bin_path[32] = "/ticket_list.bin"; save_data_file_ctx_t ticket_file; if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { @@ -503,7 +520,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title } void dump_keys() { - key_derivation_ctx_t keys; + key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; sd_mount(); @@ -544,9 +561,10 @@ void dump_keys() { // Master key derivation if (h_cfg.t210b01) { - // todo: derive mariko master keys + _derive_master_key_mariko(pkg1_id->kb, &keys); + _derive_master_keys_post_620(pkg1_id->kb, &keys); } else { - _derive_master_keys_post_620_erista(pkg1_id->kb, &keys); + _derive_master_keys_post_620(pkg1_id->kb, &keys); _derive_master_keys_from_keyblobs(&keys); } @@ -625,7 +643,7 @@ void dump_keys() { goto get_titlekeys; } - u8 read_buf[0x20] = {0}; + u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; @@ -669,8 +687,8 @@ get_titlekeys: keypair_generation--; for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - u8 temp_device_key[AES_128_KEY_SIZE] = {0}; - _get_device_key(7, temp_device_key, keypair_generation, keys.device_key_4x, keys.master_key[0]); + u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; + _get_device_key(7, temp_device_key, keypair_generation, keys.device_key, keys.device_key_4x, keys.master_key[0]); _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys.temp_key, NULL); se_aes_crypt_block_ecb(7, 0, keys.eticket_rsa_kek_personalized, eticket_rsa_kek_source); memcpy(keys.temp_key, keys.eticket_rsa_kek_personalized, sizeof(keys.temp_key)); @@ -724,16 +742,16 @@ key_output: ; SAVE_KEY(aes_kek_generation_source); SAVE_KEY(aes_key_generation_source); SAVE_KEY(bis_kek_source); - SAVE_KEY_FAMILY(keys.bis_key, 0); + SAVE_KEY_FAMILY_VAR(bis_key, keys.bis_key, 0); SAVE_KEY_FAMILY(bis_key_source, 0); - SAVE_KEY(keys.device_key); - SAVE_KEY(keys.device_key_4x); - SAVE_KEY(keys.eticket_rsa_kek); - SAVE_KEY(keys.eticket_rsa_kek_personalized); + SAVE_KEY_VAR(device_key, keys.device_key); + SAVE_KEY_VAR(device_key_4x, keys.device_key_4x); + SAVE_KEY_VAR(eticket_rsa_kek, keys.eticket_rsa_kek); + SAVE_KEY_VAR(eticket_rsa_kek_personalized, keys.eticket_rsa_kek_personalized); SAVE_KEY(eticket_rsa_kek_source); SAVE_KEY(eticket_rsa_kekek_source); SAVE_KEY(header_kek_source); - SAVE_KEY(keys.header_key); + SAVE_KEY_VAR(header_key, keys.header_key); SAVE_KEY(header_key_source); SAVE_KEY_FAMILY_VAR(key_area_key_application, keys.key_area_key[0], 0); SAVE_KEY_VAR(key_area_key_application_source, key_area_key_sources[0]); @@ -741,17 +759,17 @@ key_output: ; SAVE_KEY_VAR(key_area_key_ocean_source, key_area_key_sources[1]); SAVE_KEY_FAMILY_VAR(key_area_key_system, keys.key_area_key[2], 0); SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); - SAVE_KEY_FAMILY(keys.keyblob, 0); - SAVE_KEY_FAMILY(keys.keyblob_key, 0); + SAVE_KEY_FAMILY_VAR(keyblob, keys.keyblob, 0); + SAVE_KEY_FAMILY_VAR(keyblob_key, keys.keyblob_key, 0); SAVE_KEY_FAMILY(keyblob_key_source, 0); - SAVE_KEY_FAMILY(keys.keyblob_mac_key, 0); + SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys.keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); - SAVE_KEY_FAMILY(keys.master_kek, 0); + SAVE_KEY_FAMILY_VAR(master_kek, keys.master_kek, 0); SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); - SAVE_KEY_FAMILY(keys.master_key, 0); + SAVE_KEY_FAMILY_VAR(master_key, keys.master_key, 0); SAVE_KEY(master_key_source); - SAVE_KEY_FAMILY(keys.package1_key, 0); - SAVE_KEY_FAMILY(keys.package2_key, 0); + SAVE_KEY_FAMILY_VAR(package1_key, keys.package1_key, 0); + SAVE_KEY_FAMILY_VAR(package2_key, keys.package2_key, 0); SAVE_KEY(package2_key_source); SAVE_KEY(per_console_key_source); SAVE_KEY(retail_specific_aes_key_source); @@ -762,7 +780,7 @@ key_output: ; keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; SAVE_KEY_VAR(rsa_private_kek_generation_source, keys.temp_key); SAVE_KEY(save_mac_kek_source); - SAVE_KEY(keys.save_mac_key); + SAVE_KEY_VAR(save_mac_key, keys.save_mac_key); SAVE_KEY(save_mac_key_source); SAVE_KEY(save_mac_sd_card_kek_source); SAVE_KEY(save_mac_sd_card_key_source); @@ -770,12 +788,12 @@ key_output: ; SAVE_KEY(sd_card_kek_source); SAVE_KEY(sd_card_nca_key_source); SAVE_KEY(sd_card_save_key_source); - SAVE_KEY(keys.sd_seed); + SAVE_KEY_VAR(sd_seed, keys.sd_seed); SAVE_KEY_VAR(secure_boot_key, keys.sbk); - SAVE_KEY(keys.ssl_rsa_kek); + SAVE_KEY_VAR(ssl_rsa_kek, keys.ssl_rsa_kek); SAVE_KEY(ssl_rsa_kek_source_x); SAVE_KEY(ssl_rsa_kek_source_y); - SAVE_KEY_FAMILY(keys.titlekek, 0); + SAVE_KEY_FAMILY_VAR(titlekek, keys.titlekek, 0); SAVE_KEY(titlekek_source); _save_key("tsec_key", keys.tsec_keys, AES_128_KEY_SIZE, text_buffer); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) @@ -861,13 +879,15 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons se_aes_unwrap_key(ks, ks, key_seed); } -static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *master_key) { - if (revision < KB_FIRMWARE_VERSION_400) +static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *new_device_key, const void *master_key) { + if (revision < KB_FIRMWARE_VERSION_400) { memcpy(out_device_key, device_key, AES_128_KEY_SIZE); + return; + } revision -= KB_FIRMWARE_VERSION_400; - u8 temp_key[AES_128_KEY_SIZE] = {0}; - se_aes_key_set(ks, device_key, AES_128_KEY_SIZE); + u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; + se_aes_key_set(ks, new_device_key, AES_128_KEY_SIZE); se_aes_crypt_ecb(ks, 0, temp_key, AES_128_KEY_SIZE, device_master_key_source_sources[revision], AES_128_KEY_SIZE); se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, device_master_kek_sources[revision]); @@ -875,7 +895,9 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo } static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { - u8 plaintext[RSA_2048_KEY_SIZE] = {0}, ciphertext[RSA_2048_KEY_SIZE] = {0}, work[RSA_2048_KEY_SIZE] = {0}; + u8 plaintext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, + ciphertext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, + work[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}; // 0xCAFEBABE plaintext[0xfc] = 0xca; plaintext[0xfd] = 0xfe; plaintext[0xfe] = 0xba; plaintext[0xff] = 0xbe; diff --git a/source/main.c b/source/main.c index 961a572..e5fc205 100644 --- a/source/main.c +++ b/source/main.c @@ -297,27 +297,30 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) sdmmc_t sdmmc; sdmmc_storage_t storage; sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); - u8 *bct = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - sdmmc_storage_read(&storage, 0x2200 / NX_EMMC_BLOCKSIZE, 1, bct); + sdmmc_storage_read(&storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); sdmmc_storage_end(&storage); - sprintf(sysnand_label + 36, "% 3d", bct[0x130] - 1); + u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset); + sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); ment_top[0].caption = sysnand_label; if (h_cfg.emummc_force_disable) { - free(bct); + free(pkg1); return; } emummc_storage_init_mmc(&storage, &sdmmc); - memset(bct, 0, NX_EMMC_BLOCKSIZE); + memset(pkg1, 0, PKG1_MAX_SIZE); emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - emummc_storage_read(&storage, 0x2200 / NX_EMMC_BLOCKSIZE, 1, bct); + emummc_storage_read(&storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); emummc_storage_end(&storage); - sprintf(emunand_label + 36, "% 3d", bct[0x130] - 1); - free(bct); + pkg1_id = pkg1_identify(pkg1 + pk1_offset); + sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + free(pkg1); ment_top[1].caption = emunand_label; } @@ -393,6 +396,19 @@ void ipl_main() ment_top[1].handler = NULL; } + // Grey out reboot to RCM option if on Mariko or patched console. + if (h_cfg.t210b01 || h_cfg.rcm_patched) + { + ment_top[6].type = MENT_CAPTION; + ment_top[6].color = 0xFF555555; + ment_top[6].handler = NULL; + } + + if (h_cfg.rcm_patched) + { + ment_top[5].handler = reboot_full; + } + // Update key generations listed in menu. _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); From 1b5a7bb302d6506d7c38203cb62e8e296d997970 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Dec 2020 19:04:59 -0700 Subject: [PATCH 092/166] nx_savedata: Fix storage length init on v5 save --- bdk/libs/nx_savedata/cached_storage.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bdk/libs/nx_savedata/cached_storage.c b/bdk/libs/nx_savedata/cached_storage.c index 52d38a3..78528a3 100644 --- a/bdk/libs/nx_savedata/cached_storage.c +++ b/bdk/libs/nx_savedata/cached_storage.c @@ -49,7 +49,7 @@ static ALWAYS_INLINE cache_block_t *cache_block_init(cached_storage_ctx_t *ctx) void save_cached_storage_init(cached_storage_ctx_t *ctx, substorage *base_storage, uint32_t block_size, uint32_t cache_size) { memcpy(&ctx->base_storage, base_storage, sizeof(substorage)); ctx->block_size = block_size; - substorage_get_size(base_storage, &ctx->length); + ctx->length = base_storage->length; ctx->cache_size = cache_size; list_init(&ctx->blocks); @@ -69,6 +69,8 @@ static void cache_block_finalize(cache_block_t **block) { } void save_cached_storage_finalize(cached_storage_ctx_t *ctx) { + if (!ctx->blocks.next) + return; LIST_FOREACH_SAFE(curr_block, &ctx->blocks) { cache_block_t *block = CONTAINER_OF(curr_block, cache_block_t, link) ; cache_block_finalize(&block); @@ -76,6 +78,8 @@ void save_cached_storage_finalize(cached_storage_ctx_t *ctx) { } static bool try_get_block_by_value(cached_storage_ctx_t *ctx, uint64_t index, cache_block_t **out_block) { + if (!ctx->blocks.next) + return false; LIST_FOREACH_ENTRY(cache_block_t, block, &ctx->blocks, link) { if (block->index == index) { *out_block = block; From 1e87828db4ada6a57b83dddff36839ed76345c3a Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Dec 2020 19:06:46 -0700 Subject: [PATCH 093/166] nx_savedata: Ensure heap safety --- bdk/libs/nx_savedata/remap_storage.c | 4 +- bdk/libs/nx_savedata/save.c | 73 ++++++++++++++++++++-------- bdk/libs/nx_savedata/storage.c | 5 -- bdk/libs/nx_savedata/storage.h | 5 +- 4 files changed, 59 insertions(+), 28 deletions(-) diff --git a/bdk/libs/nx_savedata/remap_storage.c b/bdk/libs/nx_savedata/remap_storage.c index b00c4e1..eedda6f 100644 --- a/bdk/libs/nx_savedata/remap_storage.c +++ b/bdk/libs/nx_savedata/remap_storage.c @@ -102,7 +102,7 @@ uint32_t save_remap_storage_read(remap_storage_ctx_t *ctx, void *buffer, uint64_ } uint64_t in_pos = offset; uint32_t out_pos = 0; - uint32_t remaining = count; + uint32_t remaining = (u32)count; while (remaining) { uint64_t entry_pos = in_pos - entry->entry.virtual_offset; @@ -135,7 +135,7 @@ uint32_t save_remap_storage_write(remap_storage_ctx_t *ctx, const void *buffer, } uint64_t in_pos = offset; uint32_t out_pos = 0; - uint32_t remaining = count; + uint32_t remaining = (u32)count; while (remaining) { uint64_t entry_pos = in_pos - entry->entry.virtual_offset; diff --git a/bdk/libs/nx_savedata/save.c b/bdk/libs/nx_savedata/save.c index 979c948..b7fea65 100644 --- a/bdk/libs/nx_savedata/save.c +++ b/bdk/libs/nx_savedata/save.c @@ -143,6 +143,11 @@ bool save_process(save_ctx_t *ctx) { } } + if (ctx->header.layout.version > VERSION_DISF_5) { + EPRINTF("Unsupported save version.\nLibrary must be updated."); + return false; + } + /* Initialize remap storages. */ ctx->data_remap_storage.header = &ctx->header.main_remap_header; ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; @@ -177,7 +182,7 @@ bool save_process(save_ctx_t *ctx) { return false; } - /* Initialize meta remap storage. */ + /* Initialize meta remap storage. */ substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length); ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, meta_remap_entry_size) != meta_remap_entry_size) { @@ -232,37 +237,65 @@ bool save_process(save_ctx_t *ctx) { } void save_free_contexts(save_ctx_t *ctx) { - for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { - free(ctx->data_remap_storage.segments[i].entries); + if (ctx->data_remap_storage.header) { + for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { + if (ctx->data_remap_storage.segments && ctx->data_remap_storage.segments[i].entries) + free(ctx->data_remap_storage.segments[i].entries); + } } - free(ctx->data_remap_storage.segments); - for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { - free(ctx->meta_remap_storage.segments[i].entries); + if (ctx->data_remap_storage.segments) + free(ctx->data_remap_storage.segments); + + if (ctx->meta_remap_storage.header) { + for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { + if (ctx->meta_remap_storage.segments && ctx->meta_remap_storage.segments[i].entries) + free(ctx->meta_remap_storage.segments[i].entries); + } } - free(ctx->meta_remap_storage.segments); - free(ctx->data_remap_storage.map_entries); - free(ctx->meta_remap_storage.map_entries); + if (ctx->meta_remap_storage.segments) + free(ctx->meta_remap_storage.segments); + + if (ctx->data_remap_storage.map_entries) + free(ctx->data_remap_storage.map_entries); + if (ctx->meta_remap_storage.map_entries) + free(ctx->meta_remap_storage.map_entries); + for (unsigned int i = 0; i < 2; i++) { - free(ctx->duplex_storage.layers[i].bitmap.bitmap); - free(ctx->duplex_storage.layers[i].data_a.base_storage.ctx); - free(ctx->duplex_storage.layers[i].data_b.base_storage.ctx); + if (ctx->duplex_storage.layers[i].bitmap.bitmap) + free(ctx->duplex_storage.layers[i].bitmap.bitmap); + if (ctx->duplex_storage.layers[i].data_a.base_storage.ctx) + free(ctx->duplex_storage.layers[i].data_a.base_storage.ctx); + if (ctx->duplex_storage.layers[i].data_b.base_storage.ctx) + free(ctx->duplex_storage.layers[i].data_b.base_storage.ctx); } - free(ctx->duplex_storage.layers[1].bitmap_storage.base_storage.ctx); - free(ctx->journal_storage.map.map_storage); - free(ctx->journal_storage.map.entries); + if (ctx->duplex_storage.layers[1].bitmap_storage.base_storage.ctx) + free(ctx->duplex_storage.layers[1].bitmap_storage.base_storage.ctx); + + if (ctx->journal_storage.map.map_storage) + free(ctx->journal_storage.map.map_storage); + if (ctx->journal_storage.map.entries) + free(ctx->journal_storage.map.entries); + for (unsigned int i = 0; i < 4; i++) { - free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); + if (ctx->core_data_ivfc_storage.integrity_storages[i].block_validities) + free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); save_cached_storage_finalize(&ctx->core_data_ivfc_storage.levels[i + 1]); } - free(ctx->core_data_ivfc_storage.level_validities); + if (ctx->core_data_ivfc_storage.level_validities) + free(ctx->core_data_ivfc_storage.level_validities); + if (ctx->header.layout.version >= VERSION_DISF_5) { for (unsigned int i = 0; i < 3; i++) { - free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); + if (ctx->fat_ivfc_storage.integrity_storages[i].block_validities) + free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); save_cached_storage_finalize(&ctx->fat_ivfc_storage.levels[i + 1]); } } - free(ctx->fat_ivfc_storage.level_validities); - free(ctx->fat_storage); + if (ctx->fat_ivfc_storage.level_validities) + free(ctx->fat_ivfc_storage.level_validities); + + if (ctx->fat_storage) + free(ctx->fat_storage); } static ALWAYS_INLINE bool save_flush(save_ctx_t *ctx) { diff --git a/bdk/libs/nx_savedata/storage.c b/bdk/libs/nx_savedata/storage.c index 326f051..69d88b8 100644 --- a/bdk/libs/nx_savedata/storage.c +++ b/bdk/libs/nx_savedata/storage.c @@ -45,11 +45,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -void storage_init(storage *this, const storage_vt *vt, void *ctx) { - this->vt = vt; - this->ctx = ctx; -} - void substorage_init(substorage *this, const storage_vt *vt, void *ctx, uint64_t offset, uint64_t length) { storage_init(&this->base_storage, vt, ctx); this->offset = offset; diff --git a/bdk/libs/nx_savedata/storage.h b/bdk/libs/nx_savedata/storage.h index 545a26b..5603881 100644 --- a/bdk/libs/nx_savedata/storage.h +++ b/bdk/libs/nx_savedata/storage.h @@ -51,7 +51,10 @@ typedef struct { void *ctx; } storage; -void storage_init(storage *this, const storage_vt *vt, void *ctx); +static void ALWAYS_INLINE storage_init(storage *this, const storage_vt *vt, void *ctx) { + this->vt = vt; + this->ctx = ctx; +} typedef struct { uint64_t offset; From b074d14107fcde254e9f85c5140da909fffd0292 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Dec 2020 19:08:24 -0700 Subject: [PATCH 094/166] keys: Finalize Mariko compatibility with save mac --- source/keys/keys.c | 15 ++++++++++----- source/main.c | 9 --------- source/storage/nx_emmc_bis.c | 8 ++++---- source/storage/nx_emmc_bis.h | 1 + 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index fa850bc..13a4c01 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -358,8 +358,9 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_cou se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x10, header_key_source + 0x10); } - if (_key_exists(keys->device_key)) { - _generate_kek(8, save_mac_kek_source, keys->device_key, aes_kek_generation_source, NULL); + if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { + _get_device_key(8, keys->temp_key, 0, keys->device_key, keys->device_key_4x, keys->master_key[0]); + _generate_kek(8, save_mac_kek_source, keys->temp_key, aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); } @@ -675,7 +676,7 @@ get_titlekeys: se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - if (cal0->magic != 0x304C4143) { + if (cal0->magic != MAGIC_CAL0) { EPRINTF("Invalid CAL0 magic. Check BIS key 0."); goto dismount; } @@ -880,12 +881,16 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons } static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *new_device_key, const void *master_key) { - if (revision < KB_FIRMWARE_VERSION_400) { + if (revision == KB_FIRMWARE_VERSION_100_200 && !h_cfg.t210b01) { memcpy(out_device_key, device_key, AES_128_KEY_SIZE); return; } - revision -= KB_FIRMWARE_VERSION_400; + if (revision >= KB_FIRMWARE_VERSION_400) { + revision -= KB_FIRMWARE_VERSION_400; + } else { + revision = 0; + } u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; se_aes_key_set(ks, new_device_key, AES_128_KEY_SIZE); se_aes_crypt_ecb(ks, 0, temp_key, AES_128_KEY_SIZE, device_master_key_source_sources[revision], AES_128_KEY_SIZE); diff --git a/source/main.c b/source/main.c index e5fc205..5a7d03a 100644 --- a/source/main.c +++ b/source/main.c @@ -362,15 +362,6 @@ void ipl_main() display_backlight_pwm_init(); - if (h_cfg.t210b01) - { - gfx_printf("Mariko SOC detected!\nMariko is currently unsupported\nbut stay tuned..."); - gfx_printf("\n\n Press any button to power off."); - display_backlight_brightness(h_cfg.backlight, 1000); - btn_wait(); - power_off(); - } - // Overclock BPMP. bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 243a3ee..a2d19c2 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -95,7 +95,7 @@ static int _nx_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u8 *tweak, for (u32 i = 0; i < (tweak_exp << 5); i++) _gf256_mul_x_le(tweak); - u8 orig_tweak[0x10]; + u8 orig_tweak[0x10] __attribute__((aligned(4))); memcpy(orig_tweak, tweak, 0x10); // We are assuming a 0x10-aligned sector size in this implementation. @@ -131,7 +131,7 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool force if (!system_part) return 3; // Not ready. - u8 tweak[0x10]; + u8 tweak[0x10] __attribute__((aligned(4))); u32 cluster = sector / SECTORS_PER_CLUSTER; u32 aligned_sector = cluster * SECTORS_PER_CLUSTER; u32 sector_index_in_cluster = sector % SECTORS_PER_CLUSTER; @@ -186,8 +186,8 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) static u32 prev_cluster = -1; static u32 prev_sector = 0; - static u8 tweak[0x10]; - u8 cache_tweak[0x10]; + static u8 tweak[0x10] __attribute__((aligned(4))); + u8 cache_tweak[0x10] __attribute__((aligned(4))); u32 tweak_exp = 0; bool regen_tweak = true; diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 3a6aeca..4eb5d82 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -225,6 +225,7 @@ typedef struct _nx_emmc_cal0_t u8 console_6axis_sensor_mount_type; } __attribute__((packed)) nx_emmc_cal0_t; +#define MAGIC_CAL0 0x304C4143 #define NX_EMMC_CALIBRATION_OFFSET 0x4400 #define NX_EMMC_CALIBRATION_SIZE 0x8000 #define XTS_CLUSTER_SIZE 0x4000 From b7495bd57550aad3c8d9cbe6573b0a6a03ee6361 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 10 Dec 2020 12:39:09 -0700 Subject: [PATCH 095/166] keys: Finish refactor --- source/keys/keys.c | 563 +++++++++++++++++++++++---------------------- source/keys/keys.h | 7 + 2 files changed, 301 insertions(+), 269 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 13a4c01..da1175a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -470,7 +470,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title offset = 0; terminator_reached = false; - u32 pct = 0, last_pct = 0; + u32 pct = 0, last_pct = 0, i = 0; while (offset < ticket_file.size && !terminator_reached) { if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) break; @@ -483,10 +483,14 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title last_pct = pct; tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); } - if (curr_ticket->signature_type != ticket_sig_type_rsa2048_sha256) { + if (i == file_tkey_count || curr_ticket->signature_type == 0) { terminator_reached = true; break; } + if (curr_ticket->signature_type != ticket_sig_type_rsa2048_sha256) { + i++; + continue; + } if (is_personalized) { se_rsa_exp_mod(0, curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block), curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block)); if (se_rsa_oaep_decode( @@ -500,6 +504,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title memcpy(titlekey_buffer->rights_ids[_titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); memcpy(titlekey_buffer->titlekeys[_titlekey_count], curr_ticket->titlekey_block, sizeof(titlekey_buffer->titlekeys[0])); _titlekey_count++; + i++; } } tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); @@ -520,35 +525,290 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return true; } -void dump_keys() { - key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; +static bool _derive_sd_seed(key_derivation_ctx_t *keys) { + FIL fp; + u32 read_bytes = 0; + char *private_path = malloc(200); + strcpy(private_path, "sd:/"); - sd_mount(); + if (emu_cfg.nintendo_path && (emu_cfg.enabled || !h_cfg.emummc_force_disable)) { + strcat(private_path, emu_cfg.nintendo_path); + } else { + strcat(private_path, "Nintendo"); + } + strcat(private_path, "/Contents/private"); + FRESULT fr = f_open(&fp, private_path, FA_READ | FA_OPEN_EXISTING); + free(private_path); + if (fr) { + EPRINTF("Unable to open SD seed vector. Skipping."); + return false; + } + // get sd seed verification vector + if (f_read(&fp, keys->temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { + EPRINTF("Unable to read SD seed vector. Skipping."); + f_close(&fp); + return false; + } + f_close(&fp); - display_backlight_brightness(h_cfg.backlight, 1000); - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); + // this file is small enough that parsing the savedata properly is slower + if (f_open(&fp, "bis:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); + return false; + } - gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", - colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); + u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; + for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { + if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) + break; + if (!memcmp(keys->temp_key, read_buf, sizeof(keys->temp_key))) { + memcpy(keys->sd_seed, read_buf + 0x10, sizeof(keys->sd_seed)); + break; + } + } + f_close(&fp); - _key_count = 0; - _titlekey_count = 0; - color_idx = 0; + TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); - start_time = get_tmr_us(); + return true; +} + +static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { + if (!_key_exists(keys->eticket_rsa_kek)) { + return false; + } + + gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); + + u32 buf_size = 0x4000; + rsa_keypair_t rsa_keypair = {0}; + + if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { + EPRINTF("Unable to read PRODINFO."); + return false; + } + + se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; + if (cal0->magic != MAGIC_CAL0) { + EPRINTF("Invalid CAL0 magic. Check BIS key 0."); + return false; + } + + // settings sysmodule manually zeroes this out below cal version 9 + u32 keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; + + if (keypair_generation) { + keypair_generation--; + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; + _get_device_key(7, temp_device_key, keypair_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); + _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source); + memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key)); + } else { + memcpy(keys->temp_key, keys->eticket_rsa_kek, sizeof(keys->temp_key)); + } + + se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); + se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), cal0->ext_ecc_rsa2048_eticket_key, sizeof(cal0->ext_ecc_rsa2048_eticket_key), cal0->ext_ecc_rsa2048_eticket_key_iv); + + // Check public exponent is 65537 big endian + if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { + EPRINTF("Invalid public exponent."); + return false; + } + + if (!_test_key_pair(rsa_keypair.public_exponent, rsa_keypair.private_exponent, rsa_keypair.modulus)) { + EPRINTF("Invalid keypair. Check eticket_rsa_kek."); + return false; + } + + se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); + + _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); + _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &rsa_keypair); + + gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); + + return true; +} + +static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { + // Set BIS keys. + // PRODINFO/PRODINFOF + se_aes_key_set(0, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(1, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); + // SAFE + se_aes_key_set(2, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(3, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); + // SYSTEM/USER + se_aes_key_set(4, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(5, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); + + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { + EPRINTF("Unable to set partition."); + return false; + } + // Parse eMMC GPT. + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &emmc_storage); + + emmc_part_t *system_part = nx_emmc_part_find(&gpt, "SYSTEM"); + if (!system_part) { + EPRINTF("Unable to locate System partition."); + nx_emmc_gpt_free(&gpt); + return false; + } + + nx_emmc_bis_init(system_part); + + if (f_mount(&emmc_fs, "bis:", 1)) { + EPRINTF("Unable to mount system partition."); + nx_emmc_gpt_free(&gpt); + return false; + } + + if (!_derive_sd_seed(keys)) { + EPRINTF("Unable to get SD seed."); + } + + bool res = _derive_titlekeys(keys, titlekey_buffer); + if (!res) { + EPRINTF("Unable to derive titlekeys."); + } + f_mount(NULL, "bis:", 1); + nx_emmc_gpt_free(&gpt); + + return res; +} + +static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { + char *text_buffer = NULL; + if (!sd_mount()) { + EPRINTF("Unable to mount SD."); + return; + } + + u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, 0x4000); + text_buffer = (char *)calloc(1, text_buffer_size); + + SAVE_KEY(aes_kek_generation_source); + SAVE_KEY(aes_key_generation_source); + SAVE_KEY(bis_kek_source); + SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0); + SAVE_KEY_FAMILY(bis_key_source, 0); + SAVE_KEY_VAR(device_key, keys->device_key); + SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); + SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); + SAVE_KEY_VAR(eticket_rsa_kek_personalized, keys->eticket_rsa_kek_personalized); + SAVE_KEY(eticket_rsa_kek_source); + SAVE_KEY(eticket_rsa_kekek_source); + SAVE_KEY(header_kek_source); + SAVE_KEY_VAR(header_key, keys->header_key); + SAVE_KEY(header_key_source); + SAVE_KEY_FAMILY_VAR(key_area_key_application, keys->key_area_key[0], 0); + SAVE_KEY_VAR(key_area_key_application_source, key_area_key_sources[0]); + SAVE_KEY_FAMILY_VAR(key_area_key_ocean, keys->key_area_key[1], 0); + SAVE_KEY_VAR(key_area_key_ocean_source, key_area_key_sources[1]); + SAVE_KEY_FAMILY_VAR(key_area_key_system, keys->key_area_key[2], 0); + SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); + SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0); + SAVE_KEY_FAMILY_VAR(keyblob_key, keys->keyblob_key, 0); + SAVE_KEY_FAMILY(keyblob_key_source, 0); + SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0); + SAVE_KEY(keyblob_mac_key_source); + SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); + SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); + SAVE_KEY_FAMILY_VAR(master_key, keys->master_key, 0); + SAVE_KEY(master_key_source); + SAVE_KEY_FAMILY_VAR(package1_key, keys->package1_key, 0); + SAVE_KEY_FAMILY_VAR(package2_key, keys->package2_key, 0); + SAVE_KEY(package2_key_source); + SAVE_KEY(per_console_key_source); + SAVE_KEY(retail_specific_aes_key_source); + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + SAVE_KEY_VAR(rsa_oaep_kek_generation_source, keys->temp_key); + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + SAVE_KEY_VAR(rsa_private_kek_generation_source, keys->temp_key); + SAVE_KEY(save_mac_kek_source); + SAVE_KEY_VAR(save_mac_key, keys->save_mac_key); + SAVE_KEY(save_mac_key_source); + SAVE_KEY(save_mac_sd_card_kek_source); + SAVE_KEY(save_mac_sd_card_key_source); + SAVE_KEY(sd_card_custom_storage_key_source); + SAVE_KEY(sd_card_kek_source); + SAVE_KEY(sd_card_nca_key_source); + SAVE_KEY(sd_card_save_key_source); + SAVE_KEY_VAR(sd_seed, keys->sd_seed); + SAVE_KEY_VAR(secure_boot_key, keys->sbk); + SAVE_KEY_VAR(ssl_rsa_kek, keys->ssl_rsa_kek); + SAVE_KEY(ssl_rsa_kek_source_x); + SAVE_KEY(ssl_rsa_kek_source_y); + SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); + SAVE_KEY(titlekek_source); + _save_key("tsec_key", keys->tsec_keys, AES_128_KEY_SIZE, text_buffer); + if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) + _save_key("tsec_root_key", keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); + + end_time = get_tmr_us(); + gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); + gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); + + f_mkdir("sd:/switch"); + char keyfile_path[30] = "sd:/switch/prod.keys"; + if (fuse_read_odm(4) & 3) + sprintf(&keyfile_path[11], "dev.keys"); + + FILINFO fno; + if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); + } else + EPRINTF("Unable to save keys to SD."); + + if (_titlekey_count == 0) { + free(text_buffer); + return; + } + memset(text_buffer, 0, text_buffer_size); + + titlekey_text_buffer_t *titlekey_text = (titlekey_text_buffer_t *)text_buffer; + + for (u32 i = 0; i < _titlekey_count; i++) { + for (u32 j = 0; j < AES_128_KEY_SIZE; j++) + sprintf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); + sprintf(titlekey_text[i].equals, " = "); + for (u32 j = 0; j < AES_128_KEY_SIZE; j++) + sprintf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); + sprintf(titlekey_text[i].newline, "\n"); + } + sprintf(&keyfile_path[11], "title.keys"); + if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); + } else + EPRINTF("Unable to save titlekeys to SD."); + + free(text_buffer); +} + +static void _derive_keys() { u32 start_whole_operation_time = get_tmr_us(); - sdmmc_t sdmmc; const pkg1_id_t *pkg1_id; u8 *pkg1 = _read_pkg1(&sdmmc, &pkg1_id); if (!pkg1) { - goto out_wait; + return; } u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; bool res = true; + key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; if (!h_cfg.t210b01) { tsec_ctxt_t tsec_ctxt; @@ -557,7 +817,7 @@ void dump_keys() { } free(pkg1); if (res == false) { - goto out_wait; + return; } // Master key derivation @@ -577,269 +837,34 @@ void dump_keys() { _derive_misc_keys(&keys, &derivable_key_count); - if (!_key_exists(keys.bis_key[2])) - { - EPRINTF("Missing FS keys. Skipping SD seed and titlekeys."); - goto key_output; - } - - FILINFO fno; - FIL fp; - u32 read_bytes = 0; - - // Set BIS keys. - // PRODINFO/PRODINFOF - se_aes_key_set(0, keys.bis_key[0] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(1, keys.bis_key[0] + 0x10, AES_128_KEY_SIZE); - // SAFE - se_aes_key_set(2, keys.bis_key[1] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(3, keys.bis_key[1] + 0x10, AES_128_KEY_SIZE); - // SYSTEM/USER - se_aes_key_set(4, keys.bis_key[2] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(5, keys.bis_key[2] + 0x10, AES_128_KEY_SIZE); - - if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { - EPRINTF("Unable to set partition."); - goto out_wait; - } - // Parse eMMC GPT. - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &emmc_storage); - - emmc_part_t *system_part = nx_emmc_part_find(&gpt, "SYSTEM"); - if (!system_part) { - EPRINTF("Unable to locate System partition."); - goto key_output; - } - - nx_emmc_bis_init(system_part); - - if (f_mount(&emmc_fs, "bis:", 1)) { - EPRINTF("Unable to mount system partition."); - goto key_output; - } - - char private_path[200] = "sd:/"; - if (emu_cfg.nintendo_path && (emu_cfg.enabled || !h_cfg.emummc_force_disable)) { - strcat(private_path, emu_cfg.nintendo_path); - } else { - strcat(private_path, "Nintendo"); - } - strcat(private_path, "/Contents/private"); - if (f_open(&fp, private_path, FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open SD seed vector. Skipping."); - goto get_titlekeys; - } - // get sd seed verification vector - if (f_read(&fp, keys.temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { - EPRINTF("Unable to read SD seed vector. Skipping."); - f_close(&fp); - goto get_titlekeys; - } - f_close(&fp); - - // this file is so small that parsing the savedata properly would take longer - if (f_open(&fp, "bis:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); - goto get_titlekeys; - } - - u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; - for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { - if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) - break; - if (!memcmp(keys.temp_key, read_buf, sizeof(keys.temp_key))) { - memcpy(keys.sd_seed, read_buf + 0x10, sizeof(keys.sd_seed)); - break; - } - } - f_close(&fp); - - TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); - -get_titlekeys: - if (!_key_exists(keys.eticket_rsa_kek)) - goto dismount; - - gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - - u32 buf_size = 0x4000; - rsa_keypair_t rsa_keypair = {0}; - titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; - if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { - EPRINTF("Unable to read PRODINFO."); - goto dismount; - } - - se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); - - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - if (cal0->magic != MAGIC_CAL0) { - EPRINTF("Invalid CAL0 magic. Check BIS key 0."); - goto dismount; - } - - // settings sysmodule manually zeroes this out below cal version 9 - u32 keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; - - if (keypair_generation) { - keypair_generation--; - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; - _get_device_key(7, temp_device_key, keypair_generation, keys.device_key, keys.device_key_4x, keys.master_key[0]); - _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys.temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, keys.eticket_rsa_kek_personalized, eticket_rsa_kek_source); - memcpy(keys.temp_key, keys.eticket_rsa_kek_personalized, sizeof(keys.temp_key)); + // BIS key for SYSTEM partition + if (_key_exists(keys.bis_key[2])) { + _derive_emmc_keys(&keys, titlekey_buffer); } else { - memcpy(keys.temp_key, keys.eticket_rsa_kek, sizeof(keys.temp_key)); + EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); } - se_aes_key_set(6, keys.temp_key, sizeof(keys.temp_key)); - se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), cal0->ext_ecc_rsa2048_eticket_key, sizeof(cal0->ext_ecc_rsa2048_eticket_key), cal0->ext_ecc_rsa2048_eticket_key_iv); + _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time, derivable_key_count); +} - // Check public exponent is 65537 big endian - if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { - EPRINTF("Invalid public exponent."); - goto dismount; - } +void dump_keys() { + display_backlight_brightness(h_cfg.backlight, 1000); + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); - if (!_test_key_pair(rsa_keypair.public_exponent, rsa_keypair.private_exponent, rsa_keypair.modulus)) { - EPRINTF("Invalid keypair. Check eticket_rsa_kek."); - goto dismount; - } + gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", + colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); - se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); + _key_count = 0; + _titlekey_count = 0; + color_idx = 0; - _get_titlekeys_from_save(buf_size, keys.save_mac_key, titlekey_buffer, NULL); - _get_titlekeys_from_save(buf_size, keys.save_mac_key, titlekey_buffer, &rsa_keypair); + start_time = get_tmr_us(); - gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); + _derive_keys(); -dismount: ; - - f_mount(NULL, "bis:", 1); - nx_emmc_gpt_free(&gpt); - -key_output: ; - char *text_buffer = NULL; - if (!sd_mount()) { - EPRINTF("Unable to mount SD."); - goto free_buffers; - } - - typedef struct { - char rights_id[0x20]; - char equals[3]; - char titlekey[0x20]; - char newline[1]; - } titlekey_text_buffer_t; - - u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, 0x4000); - text_buffer = (char *)calloc(1, text_buffer_size); - - SAVE_KEY(aes_kek_generation_source); - SAVE_KEY(aes_key_generation_source); - SAVE_KEY(bis_kek_source); - SAVE_KEY_FAMILY_VAR(bis_key, keys.bis_key, 0); - SAVE_KEY_FAMILY(bis_key_source, 0); - SAVE_KEY_VAR(device_key, keys.device_key); - SAVE_KEY_VAR(device_key_4x, keys.device_key_4x); - SAVE_KEY_VAR(eticket_rsa_kek, keys.eticket_rsa_kek); - SAVE_KEY_VAR(eticket_rsa_kek_personalized, keys.eticket_rsa_kek_personalized); - SAVE_KEY(eticket_rsa_kek_source); - SAVE_KEY(eticket_rsa_kekek_source); - SAVE_KEY(header_kek_source); - SAVE_KEY_VAR(header_key, keys.header_key); - SAVE_KEY(header_key_source); - SAVE_KEY_FAMILY_VAR(key_area_key_application, keys.key_area_key[0], 0); - SAVE_KEY_VAR(key_area_key_application_source, key_area_key_sources[0]); - SAVE_KEY_FAMILY_VAR(key_area_key_ocean, keys.key_area_key[1], 0); - SAVE_KEY_VAR(key_area_key_ocean_source, key_area_key_sources[1]); - SAVE_KEY_FAMILY_VAR(key_area_key_system, keys.key_area_key[2], 0); - SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); - SAVE_KEY_FAMILY_VAR(keyblob, keys.keyblob, 0); - SAVE_KEY_FAMILY_VAR(keyblob_key, keys.keyblob_key, 0); - SAVE_KEY_FAMILY(keyblob_key_source, 0); - SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys.keyblob_mac_key, 0); - SAVE_KEY(keyblob_mac_key_source); - SAVE_KEY_FAMILY_VAR(master_kek, keys.master_kek, 0); - SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); - SAVE_KEY_FAMILY_VAR(master_key, keys.master_key, 0); - SAVE_KEY(master_key_source); - SAVE_KEY_FAMILY_VAR(package1_key, keys.package1_key, 0); - SAVE_KEY_FAMILY_VAR(package2_key, keys.package2_key, 0); - SAVE_KEY(package2_key_source); - SAVE_KEY(per_console_key_source); - SAVE_KEY(retail_specific_aes_key_source); - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - SAVE_KEY_VAR(rsa_oaep_kek_generation_source, keys.temp_key); - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys.temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - SAVE_KEY_VAR(rsa_private_kek_generation_source, keys.temp_key); - SAVE_KEY(save_mac_kek_source); - SAVE_KEY_VAR(save_mac_key, keys.save_mac_key); - SAVE_KEY(save_mac_key_source); - SAVE_KEY(save_mac_sd_card_kek_source); - SAVE_KEY(save_mac_sd_card_key_source); - SAVE_KEY(sd_card_custom_storage_key_source); - SAVE_KEY(sd_card_kek_source); - SAVE_KEY(sd_card_nca_key_source); - SAVE_KEY(sd_card_save_key_source); - SAVE_KEY_VAR(sd_seed, keys.sd_seed); - SAVE_KEY_VAR(secure_boot_key, keys.sbk); - SAVE_KEY_VAR(ssl_rsa_kek, keys.ssl_rsa_kek); - SAVE_KEY(ssl_rsa_kek_source_x); - SAVE_KEY(ssl_rsa_kek_source_y); - SAVE_KEY_FAMILY_VAR(titlekek, keys.titlekek, 0); - SAVE_KEY(titlekek_source); - _save_key("tsec_key", keys.tsec_keys, AES_128_KEY_SIZE, text_buffer); - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - _save_key("tsec_root_key", keys.tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); - - end_time = get_tmr_us(); - gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); - gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); - - f_mkdir("sd:/switch"); - char keyfile_path[30] = "sd:/switch/"; - if (!(fuse_read_odm(4) & 3)) - sprintf(&keyfile_path[11], "prod.keys"); - else - sprintf(&keyfile_path[11], "dev.keys"); - if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { - gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); - } else - EPRINTF("Unable to save keys to SD."); - - if (_titlekey_count == 0) - goto free_buffers; - memset(text_buffer, 0, text_buffer_size); - - titlekey_text_buffer_t *titlekey_text = (titlekey_text_buffer_t *)text_buffer; - - for (u32 i = 0; i < _titlekey_count; i++) { - for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - sprintf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); - sprintf(titlekey_text[i].equals, " = "); - for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - sprintf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); - sprintf(titlekey_text[i].newline, "\n"); - } - sprintf(&keyfile_path[11], "title.keys"); - if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { - gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); - } else - EPRINTF("Unable to save titlekeys to SD."); - -free_buffers: - free(text_buffer); - -out_wait: emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; diff --git a/source/keys/keys.h b/source/keys/keys.h index 59284c2..b3018a5 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -113,6 +113,13 @@ typedef struct { keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; } key_derivation_ctx_t; +typedef struct { + char rights_id[0x20]; + char equals[3]; + char titlekey[0x20]; + char newline[1]; +} titlekey_text_buffer_t; + #define TPRINTF(text) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", end_time - start_time); \ From 89ef341621aded8ba078b303fe34861997d52e49 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 10 Dec 2020 18:05:36 -0700 Subject: [PATCH 096/166] keys: Dump partials for Mariko keyslot bruteforce --- bdk/sec/se.c | 6 ++++++ bdk/sec/se.h | 1 + source/keys/keys.c | 53 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index de7fb9b..2f76985 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -285,6 +285,12 @@ void se_aes_key_set(u32 ks, const void *key, u32 size) } } +void se_aes_key_partial_set(u32 ks, u32 index, u32 data) +{ + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | index; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data; +} + void se_aes_iv_set(u32 ks, const void *iv) { u32 data[TEGRA_SE_AES_BLOCK_SIZE / 4]; diff --git a/bdk/sec/se.h b/bdk/sec/se.h index 9126d7f..400d865 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -27,6 +27,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags); u32 se_key_acc_ctrl_get(u32 ks); void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_iv_set(u32 ks, const void *iv); +void se_aes_key_partial_set(u32 ks, u32 index, u32 data); void se_aes_key_get(u32 ks, void *key, u32 size); void se_aes_key_clear(u32 ks); void se_aes_iv_clear(u32 ks); diff --git a/source/keys/keys.c b/source/keys/keys.c index da1175a..3e4a10a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -93,8 +93,6 @@ static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; } -#define RELOC_META_OFF 0x7C - static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { if (emummc_storage_init_mmc(&emmc_storage, sdmmc)) { EPRINTF("Unable to init MMC."); @@ -124,6 +122,8 @@ static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { return pkg1; } +#define RELOC_META_OFF 0x7C + static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { @@ -163,10 +163,7 @@ static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { } gfx_printf(" done"); f_close(&fp); - gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); - gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); - gfx_printf("\n to /sept/payload.bak\n\n"); - gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); + gfx_printf("%k\nRebooting to sept...\n\n", colors[(color_idx++) % 6]); sdmmc_storage_end(&emmc_storage); if (!reboot_to_sept((u8 *)tsec_fw, tsec_size, kb)) { return false; @@ -286,7 +283,6 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { } se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); - se_aes_key_set(9, keys->sbk, sizeof(keys->sbk)); if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblobs."); @@ -295,7 +291,7 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); se_aes_crypt_block_ecb(8, 0, keys->keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) - se_aes_crypt_block_ecb(9, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) + se_aes_crypt_block_ecb(14, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { @@ -429,8 +425,8 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } - char ticket_bin_path[32] = "/ticket.bin"; - char ticket_list_bin_path[32] = "/ticket_list.bin"; + const char ticket_bin_path[32] = "/ticket.bin"; + const char ticket_list_bin_path[32] = "/ticket_list.bin"; save_data_file_ctx_t ticket_file; if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { @@ -685,6 +681,35 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return res; } +// The security engine supports partial key override for locked keyslots +// This allows for a manageable brute force on a PC +// Then we can recover the Mariko KEK, BEK, unique SBK and SSK +static void _save_mariko_partial_keys(char *text_buffer) { + u32 pos = 0; + u32 zeros[4] = {0}; + u8 *data = malloc(4 * AES_128_KEY_SIZE); + for (u32 ks = 12; ks < 16; ks++) { + // First, encrypt zeros with complete key + se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros); + pos += sprintf(&text_buffer[pos], "%d\n", ks); + + // We only need to overwrite 3 of the dwords of the key + for (u32 i = 0; i < 3; i++) { + // Overwrite ith dword of key with zeros + se_aes_key_partial_set(ks, i, 0); + // Encrypt zeros with more of the key zeroed out + se_aes_crypt_block_ecb(ks, 1, &data[(2 - i) * AES_128_KEY_SIZE], zeros); + } + for (u32 i = 0; i < 4; i++) { + for (u32 j = 0; j < AES_128_KEY_SIZE; j++) + pos += sprintf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]); + pos += sprintf(&text_buffer[pos], "\n"); + } + } + free(data); + sd_save_to_file(text_buffer, strlen(text_buffer), "sd:/switch/partialaes.keys"); +} + static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { char *text_buffer = NULL; if (!sd_mount()) { @@ -793,6 +818,11 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl } else EPRINTF("Unable to save titlekeys to SD."); + if (h_cfg.t210b01) { + memset(text_buffer, 0, text_buffer_size); + _save_mariko_partial_keys(text_buffer); + } + free(text_buffer); } @@ -887,11 +917,12 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) } static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { - char temp_name[0x40] = {0}; + char *temp_name = calloc(1, 0x40); for (u32 i = 0; i < num_keys; i++) { sprintf(temp_name, "%s_%02x", name, i + start_key); _save_key(temp_name, data + i * len, len, outbuf); } + free(temp_name); } static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) { From 094c80f5c6a6d990ff4d1b40338c97068d2a40ae Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 10 Dec 2020 18:06:07 -0700 Subject: [PATCH 097/166] Bump version to v1.9.0 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c10c9d3..cc7b1bb 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 8 -LPVERSION_BUGFX := 4 +LPVERSION_MINOR := 9 +LPVERSION_BUGFX := 0 ################################################################################ From b77d42e8e3379e7a95249273f986213f25ed3a3f Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 5 Jan 2021 15:24:54 -0700 Subject: [PATCH 098/166] keys: Dump partial AES keys even if 0 titlekeys --- source/keys/keys.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 3e4a10a..92fa3c8 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -259,7 +259,7 @@ static void _derive_master_keys_post_620(u32 pkg1_kb, key_derivation_ctx_t *keys memset(keys->master_key[kb], 0, AES_128_KEY_SIZE); } if (_key_exists(keys->temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.\n Check sept files on SD and retry.", pkg1_kb); + EPRINTFARGS("Unable to derive master key. kb = %d.", pkg1_kb); memset(keys->master_key, 0, sizeof(keys->master_key)); } } @@ -576,7 +576,6 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - u32 buf_size = 0x4000; rsa_keypair_t rsa_keypair = {0}; if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { @@ -624,6 +623,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); + const u32 buf_size = 0x4000; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &rsa_keypair); @@ -708,6 +708,7 @@ static void _save_mariko_partial_keys(char *text_buffer) { } free(data); sd_save_to_file(text_buffer, strlen(text_buffer), "sd:/switch/partialaes.keys"); + gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]); } static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { @@ -796,6 +797,11 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl } else EPRINTF("Unable to save keys to SD."); + if (h_cfg.t210b01) { + memset(text_buffer, 0, text_buffer_size); + _save_mariko_partial_keys(text_buffer); + } + if (_titlekey_count == 0) { free(text_buffer); return; @@ -818,11 +824,6 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl } else EPRINTF("Unable to save titlekeys to SD."); - if (h_cfg.t210b01) { - memset(text_buffer, 0, text_buffer_size); - _save_mariko_partial_keys(text_buffer); - } - free(text_buffer); } From b3f6e055b2d0d09eed5d421f9ceb659095eadc28 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 5 Jan 2021 15:38:53 -0700 Subject: [PATCH 099/166] Reconfigure messages to conserve payload size --- source/hos/sept.c | 1 - source/keys/keys.c | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/source/hos/sept.c b/source/hos/sept.c index 5e6ef73..94b86f6 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -157,7 +157,6 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) f_close(&fp); sd_unmount(); - gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); diff --git a/source/keys/keys.c b/source/keys/keys.c index 92fa3c8..cfd3952 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -127,8 +127,7 @@ static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { sd_mount(); if (!f_stat("sd:/sept/payload.bak", NULL)) { - if (f_unlink("sd:/sept/payload.bin")) - gfx_printf("%kNote: no payload.bin already in /sept\n", colors[(color_idx++) % 6]); + f_unlink("sd:/sept/payload.bin"); f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); } @@ -152,7 +151,7 @@ static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); u32 payload_size = relocator->end - IPL_LOAD_ADDR; if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { - EPRINTF("Unable to open /sept/payload.bin to write."); + EPRINTF("Unable to write self to /sept/payload.bin."); return false; } gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); From 20c0df3715d1033817fe685d15dca4ab3b81939f Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Apr 2021 16:43:44 -0600 Subject: [PATCH 100/166] Validate pkg1_identify result for main menu --- source/main.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/source/main.c b/source/main.c index 5a7d03a..d304c8f 100644 --- a/source/main.c +++ b/source/main.c @@ -303,13 +303,15 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) sdmmc_storage_end(&storage); u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset); - sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); - ment_top[0].caption = sysnand_label; - if (h_cfg.emummc_force_disable) - { - free(pkg1); - return; + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset); + if (pkg1_id) { + sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + ment_top[0].caption = sysnand_label; + if (h_cfg.emummc_force_disable) + { + free(pkg1); + return; + } } emummc_storage_init_mmc(&storage, &sdmmc); @@ -319,9 +321,11 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) emummc_storage_end(&storage); pkg1_id = pkg1_identify(pkg1 + pk1_offset); - sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); - free(pkg1); - ment_top[1].caption = emunand_label; + if (pkg1_id) { + sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + free(pkg1); + ment_top[1].caption = emunand_label; + } } extern void pivot_stack(u32 stack_top); From dd3add9327bae1dfd76a95e9b546f17c18358f3b Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Apr 2021 16:44:08 -0600 Subject: [PATCH 101/166] pkg1: Recognize 12.0.0 --- source/hos/pkg1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 23b25bd..56be761 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -39,6 +39,7 @@ static const pkg1_id_t _pkg1_ids[] = { { "20191021113848", 10}, //9.1.0 { "20200303104606", 10}, //10.0.0 - 10.2.0 { "20201030110855", 10}, //11.0.0 + { "20210129111626", 10}, //12.0.0 { NULL } //End. }; From 7defba226a97dcf85016a448af4ecb3b09c5f894 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Apr 2021 16:45:21 -0600 Subject: [PATCH 102/166] Bump version to v1.9.1 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cc7b1bb..c32db7e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 0 +LPVERSION_BUGFX := 1 ################################################################################ From 93909f149ef36ccdef1ac9e72849a101e3133b5d Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 10:33:56 -0600 Subject: [PATCH 103/166] pkg1: Recognize 12.0.2 --- source/hos/pkg1.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 56be761..9cf549c 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -34,12 +34,13 @@ static const pkg1_id_t _pkg1_ids[] = { { "20181218175730", 7 }, //7.0.0 { "20190208150037", 7 }, //7.0.1 { "20190314172056", 7 }, //8.0.0 - 8.0.1 - { "20190531152432", 8 }, //8.1.0 + { "20190531152432", 8 }, //8.1.0 - 8.1.1 { "20190809135709", 9 }, //9.0.0 - 9.0.1 - { "20191021113848", 10}, //9.1.0 + { "20191021113848", 10}, //9.1.0 - 9.2.0 { "20200303104606", 10}, //10.0.0 - 10.2.0 - { "20201030110855", 10}, //11.0.0 - { "20210129111626", 10}, //12.0.0 + { "20201030110855", 10}, //11.0.0 - 11.0.1 + { "20210129111626", 10}, //12.0.0 - 12.0.1 + { "20210422145837", 10}, //12.0.2 { NULL } //End. }; From a7712b173c8bd869c6a1f8ce49255263a9692101 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 15:38:34 -0600 Subject: [PATCH 104/166] Update to hekate bdk 5.5.6 --- Makefile | 5 +- bdk/{gfx => display}/di.c | 52 ++- bdk/{gfx => display}/di.h | 12 +- bdk/{gfx => display}/di.inl | 0 bdk/ianos/ianos.c | 5 + bdk/input/als.c | 11 +- bdk/input/joycon.c | 137 ++++--- bdk/input/touch.c | 87 +++-- bdk/input/touch.h | 30 +- bdk/libs/compr/lz4.c | 25 +- bdk/libs/fatfs/diskio.h | 4 +- bdk/libs/fatfs/ff.c | 44 ++- bdk/libs/fatfs/ff.h | 8 +- bdk/libs/lv_conf.h | 2 +- bdk/libs/lvgl/lv_misc/lv_log.c | 2 +- bdk/mem/mc.c | 18 +- bdk/mem/minerva.c | 32 +- bdk/mem/minerva.h | 1 + bdk/mem/sdram.c | 27 +- bdk/mem/sdram.h | 10 +- bdk/mem/sdram_config.inl | 18 +- bdk/mem/sdram_config_t210b01.inl | 30 +- bdk/memory_map.h | 15 +- bdk/module.h | 5 + bdk/power/max77620.h | 244 +++++++----- bdk/power/max7762x.c | 308 +++++++++++---- bdk/power/max7762x.h | 116 +++--- bdk/power/max77812.h | 29 +- bdk/power/regulator_5v.c | 23 +- bdk/power/regulator_5v.h | 7 +- bdk/sec/se.c | 342 ++++++++--------- bdk/sec/se.h | 6 +- bdk/sec/se_t210.h | 637 ++++++++++++++----------------- bdk/sec/tsec.c | 14 +- bdk/soc/bpmp.c | 27 +- bdk/soc/bpmp.h | 5 +- bdk/soc/ccplex.c | 61 +-- bdk/soc/clock.c | 86 ++++- bdk/soc/clock.h | 164 +++++++- bdk/soc/fuse.c | 32 +- bdk/soc/fuse.h | 12 +- bdk/soc/hw_init.c | 93 +++-- bdk/soc/hw_init.h | 5 +- bdk/soc/i2c.c | 8 +- bdk/soc/irq.c | 14 +- bdk/soc/pmc.c | 60 ++- bdk/soc/pmc.h | 52 ++- bdk/soc/uart.c | 7 +- bdk/soc/uart.h | 11 + bdk/storage/mmc.h | 14 +- bdk/storage/nx_sd.h | 5 +- bdk/storage/ramdisk.c | 39 +- bdk/storage/ramdisk.h | 4 +- bdk/storage/sd.h | 115 +++--- bdk/storage/sdmmc.c | 390 ++++++++++--------- bdk/storage/sdmmc.h | 48 ++- bdk/storage/sdmmc_driver.c | 42 +- bdk/storage/sdmmc_driver.h | 2 +- bdk/thermal/fan.c | 22 +- bdk/thermal/tmp451.c | 24 +- bdk/thermal/tmp451.h | 4 + bdk/usb/usb_gadget_hid.c | 2 +- bdk/usb/usb_gadget_ums.c | 197 +++++----- bdk/usb/usb_t210.h | 1 + bdk/usb/usbd.c | 26 +- bdk/usb/usbd.h | 14 +- bdk/usb/xusbd.c | 40 +- bdk/utils/btn.c | 2 +- bdk/utils/dirlist.c | 10 +- bdk/utils/ini.c | 9 +- bdk/utils/sprintf.c | 2 +- bdk/utils/sprintf.h | 2 +- bdk/utils/types.h | 5 +- bdk/utils/util.c | 85 +++-- bdk/utils/util.h | 29 +- source/config.c | 1 + source/config.h | 1 + source/gfx/gfx.c | 43 ++- source/gfx/gfx.h | 7 +- source/gfx/tui.c | 4 +- source/hos/fss.c | 2 +- source/hos/hos.h | 26 +- source/hos/pkg1.c | 4 +- source/hos/sept.c | 2 +- source/keys/keys.c | 45 ++- source/libs/fatfs/ffconf.h | 2 +- source/link.ld | 3 +- source/main.c | 79 ++-- source/start.S | 6 +- source/storage/emummc.c | 31 +- source/storage/emummc.h | 12 +- source/storage/nx_emmc.c | 30 +- source/storage/nx_emmc.h | 7 +- source/storage/nx_emmc_bis.c | 11 +- source/storage/nx_sd.c | 12 +- 95 files changed, 2720 insertions(+), 1684 deletions(-) rename bdk/{gfx => display}/di.c (95%) rename bdk/{gfx => display}/di.h (98%) rename bdk/{gfx => display}/di.inl (100%) diff --git a/Makefile b/Makefile index c32db7e..a7efda8 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,11 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) #CUSTOMDEFINES += -DDEBUG +#TODO: Considering reinstating some of these when pointer warnings have been fixed. +WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow + ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) ################################################################################ diff --git a/bdk/gfx/di.c b/bdk/display/di.c similarity index 95% rename from bdk/gfx/di.c rename to bdk/display/di.c index 9d95349..1c79823 100644 --- a/bdk/gfx/di.c +++ b/bdk/display/di.c @@ -20,6 +20,7 @@ #include "di.h" #include #include +#include #include #include #include @@ -170,9 +171,9 @@ int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled) void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) { + u8 *fifo8; + u32 *fifo32; u32 host_control; - u32 fifo32[DSI_STATUS_RX_FIFO_SIZE] = {0}; - u8 *fifo8 = (u8 *)fifo32; // Enable host cmd packets during video and save host control. if (video_enabled) @@ -193,6 +194,8 @@ void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) break; default: + fifo32 = calloc(DSI_STATUS_RX_FIFO_SIZE * 8, 4); + fifo8 = (u8 *)fifo32; fifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE; fifo8[4] = cmd; memcpy(&fifo8[5], data, len); @@ -200,6 +203,7 @@ void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) for (u32 i = 0; i < (ALIGN(len, 4) / 4); i++) DSI(_DSIREG(DSI_WR_DATA)) = fifo32[i]; DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + free(fifo32); break; } @@ -215,29 +219,30 @@ void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) void display_init() { // Check if display is already initialized. - if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & BIT(CLK_L_DISP1)) + if (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_DISP1)) _display_panel_and_hw_end(true); // Get Chip ID. bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; - // T210B01: Power on SD2 regulator for supplying LD0. + // T210B01: Power on SD2 regulator for supplying LDO0. if (!tegra_t210) { // Set SD2 regulator voltage. - max77620_regulator_set_voltage(REGULATOR_SD2, 1325000); + max7762x_regulator_set_voltage(REGULATOR_SD2, 1325000); // Set slew rate and enable SD2 regulator. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT) | MAX77620_SD_CFG1_FSRADE_SD_ENABLE); - max77620_regulator_enable(REGULATOR_SD2, 1); + max7762x_regulator_enable(REGULATOR_SD2, true); } // Enable power to display panel controller. - max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. + max7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000); + max7762x_regulator_enable(REGULATOR_LDO0, true); + if (tegra_t210) - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, - MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); // T210: LD0 -> GPIO7 -> Display panel. + max77620_config_gpio(7, MAX77620_GPIO_OUTPUT_ENABLE); // T210: LD0 -> GPIO7 -> Display panel. // Enable Display Interface specific clocks. CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); @@ -293,7 +298,7 @@ void display_init() // Set DISP1 clock source and parent clock. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT. - u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 96 MHz. + u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 97.5 MHz (offset). CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; if (tegra_t210) @@ -335,9 +340,12 @@ void display_init() #if 0 // Get Display ID. - _display_id = 0xCCCCCC; + _display_id = 0xCCCCCC; // Set initial value. 4th byte cleared. display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id, DSI_VIDEO_DISABLED); #else + // Drain RX FIFO. + _display_dsi_read_rx_fifo(NULL); + // Set reply size. _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); @@ -407,11 +415,11 @@ void display_init() _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); // Configure PLLD for DISP1. - plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 230.4 MHz. + plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 234 MHz (offset). CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; if (tegra_t210) - CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP. else CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0; CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN. @@ -420,7 +428,7 @@ void display_init() DSI(_DSIREG(DSI_PAD_CONTROL_1)) = 0; DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 19); - // Set pixel clock dividers: 230.4 / 3 / 1 = 76.8 MHz. 60 Hz. + // Set pixel clock dividers: 234 / 3 / 1 = 78 MHz (offset) for 60 Hz. DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // 4: div3. exec_cfg((u32 *)DSI_BASE, _display_dsi_mode_config, 10); usleep(10000); @@ -499,6 +507,11 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; } +u32 display_get_backlight_brightness() +{ + return ((PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF); +} + static void _display_panel_and_hw_end(bool no_panel_deinit) { if (no_panel_deinit) @@ -600,11 +613,20 @@ skip_panel_deinit: void display_end() { _display_panel_and_hw_end(false); }; -u16 display_get_decoded_lcd_id() +u16 display_get_decoded_panel_id() { return _display_id; } +void display_set_decoded_panel_id(u32 id) +{ + // Decode Display ID. + _display_id = ((id >> 8) & 0xFF00) | (id & 0xFF); + + if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) + _display_id = PANEL_JDI_XXX062M; +} + void display_color_screen(u32 color) { exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8); diff --git a/bdk/gfx/di.h b/bdk/display/di.h similarity index 98% rename from bdk/gfx/di.h rename to bdk/display/di.h index e304fb6..7682bdb 100644 --- a/bdk/gfx/di.h +++ b/bdk/display/di.h @@ -650,7 +650,9 @@ * [10] 81 [26]: JDI LPM062M326A * [10] 96 [09]: JDI LAM062M109A * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) - * [20] 95 [0F]: InnoLux P062CCA-AZ2 + * [20] 95 [0F]: InnoLux P062CCA-AZ2 (Rev B1) + * [20] 96 [0F]: InnoLux P062CCA-AZ3 [UNCONFIRMED MODEL REV] + * [20] 98 [0F]: InnoLux P062CCA-??? [UNCONFIRMED MODEL REV] * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002) * @@ -671,10 +673,12 @@ * 20h: InnoLux Corporation * 30h: AU Optronics * 40h: Unknown1 + * 50h: Unknown2 (OLED? Samsung? LG?) * * Boards, Panel Size: * 0Fh: Icosa/Iowa, 6.2" * 10h: Hoag, 5.5" + * 20h: Unknown, x.x" */ enum @@ -693,8 +697,9 @@ void display_init(); void display_backlight_pwm_init(); void display_end(); -/*! Get Display panel ID. */ -u16 display_get_decoded_lcd_id(); +/*! Get/Set Display panel ID. */ +u16 display_get_decoded_panel_id(); +void display_set_decoded_panel_id(u32 id); /*! Show one single color on the display. */ void display_color_screen(u32 color); @@ -702,6 +707,7 @@ void display_color_screen(u32 color); /*! Switches screen backlight ON/OFF. */ void display_backlight(bool enable); void display_backlight_brightness(u32 brightness, u32 step_delay); +u32 display_get_backlight_brightness(); /*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ u32 *display_init_framebuffer_pitch(); diff --git a/bdk/gfx/di.inl b/bdk/display/di.inl similarity index 100% rename from bdk/gfx/di.inl rename to bdk/display/di.inl diff --git a/bdk/ianos/ianos.c b/bdk/ianos/ianos.c index 5eca1b6..8deca45 100644 --- a/bdk/ianos/ianos.c +++ b/bdk/ianos/ianos.c @@ -21,6 +21,7 @@ #include "elfload/elfload.h" #include #include +#include #include #include @@ -43,6 +44,10 @@ static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) bdkParameters->memset = (memset_t)&memset; bdkParameters->sharedHeap = &_heap; + // Extra functions. + bdkParameters->extension_magic = IANOS_EXT0; + bdkParameters->reg_voltage_set = (reg_voltage_set_t)&max7762x_regulator_set_voltage; + entrypoint(moduleConfig, bdkParameters); } diff --git a/bdk/input/als.c b/bdk/input/als.c index 97d6432..918661b 100644 --- a/bdk/input/als.c +++ b/bdk/input/als.c @@ -17,7 +17,6 @@ */ #include "als.h" -#include #include #include #include @@ -98,14 +97,16 @@ void get_als_lux(als_table_t *als_val) u8 als_init(als_table_t *als_val) { + // Enable power to ALS IC. + max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); + max7762x_regulator_enable(REGULATOR_LDO6, true); + + // Init I2C2. pinmux_config_i2c(I2C_2); clock_enable_i2c(I2C_2); i2c_init(I2C_2); - max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT | (3 << 3) | MAX77620_LDO_CFG2_ADE_ENABLE)); - + // Initialize ALS. u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN); diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c index 9a3e11a..825e347 100644 --- a/bdk/input/joycon.c +++ b/bdk/input/joycon.c @@ -1,7 +1,7 @@ /* * Joy-Con UART driver for Nintendo Switch * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 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, @@ -39,6 +39,9 @@ #define JC_WIRED_INIT_REPLY 0x94 #define JC_INIT_HANDSHAKE 0xA5 +#define JC_HORI_INPUT_RPT_CMD 0x9A +#define JC_HORI_INPUT_RPT 0x00 + #define JC_WIRED_CMD_MAC 0x01 #define JC_WIRED_CMD_10 0x10 @@ -61,8 +64,12 @@ #define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status. #define JC_BTN_MASK_R 0x0056FF -#define JC_ID_L 1 -#define JC_ID_R 2 +#define JC_ID_L 0x01 +#define JC_ID_R 0x02 +#define JC_ID_HORI 0x20 + +#define JC_CRC8_INIT 0x00 +#define JC_CRC8_POLY 0x8D enum { @@ -80,25 +87,31 @@ static const u8 init_jc[] = { 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. + 0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data and crc. }; 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. + 0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data and crc. }; -static const u8 init_finilize[] = { +static const u8 init_finalize[] = { 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. + 0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data and crc. }; 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. + 0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data and crc. +}; + +static const u8 hori_pad_status[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_HORI_INPUT_RPT_CMD, 0x01, // Hori cmd and hori subcmd. + 0x00, 0x00, 0x00, 0x00, 0x48 // Hori cmd data and crc. }; typedef struct _jc_uart_hdr_t @@ -185,8 +198,8 @@ typedef struct _joycon_ctxt_t u8 connected; } joycon_ctxt_t; -static joycon_ctxt_t jc_l; -static joycon_ctxt_t jc_r; +static joycon_ctxt_t jc_l = {0}; +static joycon_ctxt_t jc_r = {0}; static bool jc_init_done = false; static u32 hid_pkt_inc = 0; @@ -195,13 +208,29 @@ static jc_gamepad_rpt_t jc_gamepad; void jc_power_supply(u8 uart, bool enable); +static u8 jc_crc(u8 *data, u16 len) +{ + u8 crc = JC_CRC8_INIT; + u16 i, j; + for (i = 0; i < len; i++) { + crc ^= data[i]; + for (j = 0; j < 8; j++) { + if ((crc & 0x80) != 0) + crc = (u8)((crc << 1) ^ JC_CRC8_POLY); + else + crc <<= 1; + } + } + return crc; +} + 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) +static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size, bool crc) { out->uart_hdr.magic[0] = 0x19; out->uart_hdr.magic[1] = 0x01; @@ -214,14 +243,14 @@ static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u if (data) memcpy(out->data, data, size); - out->crc = 0; // wired crc8ccit can be skipped. + out->crc = crc ? jc_crc(&out->uart_hdr.total_size_msb, sizeof(out->uart_hdr.total_size_msb) + sizeof(out->cmd) + sizeof(out->data)) : 0; return sizeof(jc_wired_hdr_t); } -static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size) +static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size, bool crc) { - u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0); + u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0, crc); pkt_size += size; rpt->uart_hdr.total_size_lsb += size; @@ -234,12 +263,12 @@ static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size) return pkt_size; } -void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size) +void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size, bool crc) { u8 rpt[0x50]; memset(rpt, 0, sizeof(rpt)); - u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size); + u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size, crc); joycon_send_raw(uart, rpt, rpt_size); } @@ -275,18 +304,18 @@ void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size) 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); + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false); if (send_l_rumble) - jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10); + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false); // 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); + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10, false); if (send_l_rumble) - jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10); + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10, false); msleep(15); @@ -297,21 +326,21 @@ void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size) 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); + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false); if (send_l_rumble) - jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10); + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false); } else { + bool crc_needed = (jc_l.uart == uart) ? (jc_l.type & JC_ID_HORI) : (jc_r.type & JC_ID_HORI); + 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; - - jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size); + jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed); } } @@ -333,6 +362,7 @@ static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size) switch (hid_pkt->cmd) { + case JC_HORI_INPUT_RPT: case JC_HID_INPUT_RPT: btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16; @@ -412,6 +442,7 @@ 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_HORI_INPUT_RPT_CMD: case JC_WIRED_HID: jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]); break; @@ -432,7 +463,7 @@ static void jc_rcv_pkt(joycon_ctxt_t *jc) // Check if device stopped sending data. u32 uart_irq = uart_get_IIR(jc->uart); - if ((uart_irq & 0x8) != 0x8) + if (uart_irq != UART_IIR_REDI) return; u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0x100); @@ -474,10 +505,15 @@ static bool jc_send_init_rumble(joycon_ctxt_t *jc) static void jc_req_nx_pad_status(joycon_ctxt_t *jc) { - bool sent_rumble = jc_send_init_rumble(jc); + bool is_nxpad = !(jc->type & JC_ID_HORI); - if (sent_rumble) - return; + if (is_nxpad) + { + bool sent_rumble = jc_send_init_rumble(jc); + + if (sent_rumble) + return; + } if (jc->last_status_req_time > get_tmr_ms() || !jc->connected) return; @@ -488,7 +524,10 @@ static void jc_req_nx_pad_status(joycon_ctxt_t *jc) else gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); - joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status)); + if (is_nxpad) + joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status)); + else + joycon_send_raw(jc->uart, hori_pad_status, sizeof(hori_pad_status)); // Turn Joy-Con detect on. if (jc->uart == UART_B) @@ -655,24 +694,31 @@ retry: void jc_deinit() { + // Disable power. + jc_power_supply(UART_B, false); + jc_power_supply(UART_C, false); + + // 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); + // Send sleep command. u8 data = HCI_STATE_SLEEP; - if (jc_r.connected) + if (jc_r.connected && !(jc_r.type & JC_ID_HORI)) { jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1); jc_rcv_pkt(&jc_r); } - if (jc_l.connected) + if (jc_l.connected && !(jc_l.type & JC_ID_HORI)) { jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1); jc_rcv_pkt(&jc_l); } - jc_power_supply(UART_B, false); - jc_power_supply(UART_C, false); + // Disable UART B and C clocks. + clock_disable_uart(UART_B); + clock_disable_uart(UART_C); } static void jc_init_conn(joycon_ctxt_t *jc) @@ -709,9 +755,12 @@ static void jc_init_conn(joycon_ctxt_t *jc) msleep(5); jc_rcv_pkt(jc); - joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize)); - msleep(5); - jc_rcv_pkt(jc); + if (!(jc->type & JC_ID_HORI)) + { + joycon_send_raw(jc->uart, init_finalize, sizeof(init_finalize)); + msleep(5); + jc_rcv_pkt(jc); + } // Turn Joy-Con detect on. if (jc->uart == UART_B) @@ -766,10 +815,10 @@ void jc_power_supply(u8 uart, bool enable) { if (enable) { - if (regulator_get_5v_dev_enabled(1 << uart)) + if (regulator_5v_get_dev_enabled(1 << uart)) return; - regulator_enable_5v(1 << uart); + regulator_5v_enable(1 << uart); if (jc_init_done) { @@ -799,10 +848,10 @@ void jc_power_supply(u8 uart, bool enable) } else { - if (!regulator_get_5v_dev_enabled(1 << uart)) + if (!regulator_5v_get_dev_enabled(1 << uart)) return; - regulator_disable_5v(1 << uart); + regulator_5v_disable(1 << uart); if (uart == UART_C) gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW); @@ -816,10 +865,10 @@ void jc_init_hw() jc_l.uart = UART_C; jc_r.uart = UART_B; +#if !defined(DEBUG_UART_PORT) || !(DEBUG_UART_PORT) if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG) return; -#ifndef DEBUG_UART_PORT jc_power_supply(UART_C, true); jc_power_supply(UART_B, true); @@ -836,14 +885,14 @@ void jc_init_hw() pinmux_config_uart(UART_C); // Ease the stress to APB. - bpmp_clk_rate_set(BPMP_CLK_NORMAL); + bpmp_freq_t prev_fid = 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); + bpmp_clk_rate_set(prev_fid); // Turn Joy-Con detect on. gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); diff --git a/bdk/input/touch.c b/bdk/input/touch.c index f24b53a..17d31b3 100644 --- a/bdk/input/touch.c +++ b/bdk/input/touch.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,16 @@ #include #define DPRINTF(...) gfx_printf(__VA_ARGS__) +static touch_panel_info_t _panels[] = +{ + { 0, 1, 1, 1, "NISSHA NFT-K12D" }, + { 1, 0, 1, 1, "GiS GGM6 B2X" }, + { 2, 0, 0, 0, "NISSHA NBF-K9A" }, + { 3, 1, 0, 0, "GiS 5.5\"" }, + { 4, 0, 0, 1, "Unknown" }, + { -1, 1, 0, 1, "GiS VA 6.2\"" } +}; + static int touch_command(u8 cmd, u8 *buf, u8 size) { int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd, buf, size); @@ -53,7 +62,7 @@ static int touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size) return 0; } -static int touch_wait_event(u8 event, u8 status, u32 timeout) +static int touch_wait_event(u8 event, u8 status, u32 timeout, u8 *buf) { u32 timer = get_tmr_ms() + timeout; while (true) @@ -61,7 +70,11 @@ static int touch_wait_event(u8 event, u8 status, u32 timeout) u8 tmp[8] = {0}; i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); if (tmp[1] == event && tmp[2] == status) + { + if (buf) + memcpy(buf, &tmp[3], 5); return 0; + } if (get_tmr_ms() > timer) return 1; @@ -147,10 +160,10 @@ static void _touch_parse_event(touch_event *event) event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; } - // gfx_con_setpos(&gfx_con, 0, 300); + // gfx_con_setpos(0, 300); // DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z); - // DPRINTF("0 = %02X\n1 = %02x\n2 = %02x\n3 = %02x\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); - // DPRINTF("4 = %02X\n5 = %02x\n6 = %02x\n7 = %02x\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); + // DPRINTF("0 = %02X\n1 = %02X\n2 = %02X\n3 = %02X\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); + // DPRINTF("4 = %02X\n5 = %02X\n6 = %02X\n7 = %02X\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); } void touch_poll(touch_event *event) @@ -183,16 +196,45 @@ touch_info touch_get_info() info.config_id = buf[4]; info.config_ver = buf[5]; - //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02x, Cfg Ver: %d\n", + //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02X, Cfg Ver: %d\n", // info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver); return info; } +touch_panel_info_t *touch_get_panel_vendor() +{ + u8 buf[5] = {0}; + u8 cmd = STMFTS_VENDOR_GPIO_STATE; + static touch_panel_info_t panel_info = { -2, 0, 0, 0, ""}; + + if (touch_command(STMFTS_VENDOR, &cmd, 1)) + return NULL; + + if (touch_wait_event(STMFTS_EV_VENDOR, STMFTS_VENDOR_GPIO_STATE, 2000, buf)) + return NULL; + + for (u32 i = 0; i < ARRAY_SIZE(_panels); i++) + { + touch_panel_info_t *panel = &_panels[i]; + if (buf[0] == panel->gpio0 && buf[1] == panel->gpio1 && buf[2] == panel->gpio2) + return panel; + } + + // Touch panel not found, return current gpios. + panel_info.gpio0 = buf[0]; + panel_info.gpio1 = buf[1]; + panel_info.gpio2 = buf[2]; + + return &panel_info; +} + int touch_get_fw_info(touch_fw_info_t *fw) { u8 buf[8] = {0}; + memset(fw, 0, sizeof(touch_fw_info_t)); + // Get fw address info. u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0x60 }; int res = touch_read_reg(cmd, 3, buf, 3); @@ -227,7 +269,7 @@ int touch_sys_reset() continue; } msleep(10); - if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20)) + if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL)) continue; else return 0; @@ -284,7 +326,7 @@ int touch_get_fb_info(u8 *buf) int res = 0; - for (u32 i = 0; i < 0x10000; i+=4) + for (u32 i = 0; i < 0x10000; i += 4) { if (!res) { @@ -301,9 +343,9 @@ int touch_get_fb_info(u8 *buf) int touch_sense_enable() { - // Enable auto tuning calibration and multi-touch sensing. - u8 cmd = 1; - if (touch_command(STMFTS_AUTO_CALIBRATION, &cmd, 1)) + // Switch sense mode and enable multi-touch sensing. + u8 cmd = STMFTS_FINGER_MODE; + if (touch_command(STMFTS_SWITCH_SENSE_MODE, &cmd, 1)) return 0; if (touch_command(STMFTS_MS_MT_SENSE_ON, NULL, 0)) @@ -329,19 +371,19 @@ int touch_execute_autotune() // Apply Mutual Sense Compensation tuning. if (touch_command(STMFTS_MS_CX_TUNING, NULL, 0)) return 0; - if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000)) + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000, NULL)) return 0; // Apply Self Sense Compensation tuning. if (touch_command(STMFTS_SS_CX_TUNING, NULL, 0)) return 0; - if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000)) + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000, NULL)) return 0; // Save Compensation data to EEPROM. if (touch_command(STMFTS_SAVE_CX_TUNING, NULL, 0)) return 0; - if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000)) + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000, NULL)) return 0; return touch_sense_enable(); @@ -358,12 +400,11 @@ static int touch_init() int touch_power_on() { - // Enables LDO6 for touchscreen VDD/AVDD supply - max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT | (3 << 3) | MAX77620_LDO_CFG2_ADE_ENABLE)); + // Enable LDO6 for touchscreen AVDD supply. + max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); + max7762x_regulator_enable(REGULATOR_LDO6, true); - // Configure touchscreen GPIO. + // Configure touchscreen VDD GPIO. PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; gpio_config(GPIO_PORT_J, GPIO_PIN_7, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_J, GPIO_PIN_7, GPIO_OUTPUT_ENABLE); @@ -377,7 +418,7 @@ int touch_power_on() // Configure Touscreen and GCAsic shared GPIO. PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; - gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); // GC detect. // Initialize I2C3. pinmux_config_i2c(I2C_3); @@ -385,7 +426,7 @@ int touch_power_on() i2c_init(I2C_3); // Wait for the touchscreen module to get ready. - touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20); + touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL); // Check for forced boot time calibration. if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) @@ -414,9 +455,7 @@ void touch_power_off() gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); // Disables LDO6 for touchscreen VDD, AVDD supply - max77620_regulator_enable(REGULATOR_LDO6, 0); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - MAX77620_LDO_CFG2_ADE_ENABLE | (2 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + max7762x_regulator_enable(REGULATOR_LDO6, false); clock_disable_i2c(I2C_3); } \ No newline at end of file diff --git a/bdk/input/touch.h b/bdk/input/touch.h index 9245be3..3345faa 100644 --- a/bdk/input/touch.h +++ b/bdk/input/touch.h @@ -47,19 +47,26 @@ #define STMFTS_ITO_CHECK 0xA7 #define STMFTS_RELEASEINFO 0xAA #define STMFTS_WRITE_REG 0xB6 -#define STMFTS_AUTO_CALIBRATION 0xC3 +#define STMFTS_SWITCH_SENSE_MODE 0xC3 #define STMFTS_NOISE_WRITE 0xC7 #define STMFTS_NOISE_READ 0xC8 #define STMFTS_RW_FRAMEBUFFER_REG 0xD0 #define STMFTS_SAVE_CX_TUNING 0xFC -#define STMFTS_UNK0 0xB8 //Request compensation -#define STMFTS_UNK1 0xCF -#define STMFTS_UNK2 0xF7 -#define STMFTS_UNK3 0xFA -#define STMFTS_UNK4 0xF9 +#define STMFTS_REQU_COMP_DATA 0xB8 +#define STMFTS_VENDOR 0xCF +#define STMFTS_FLASH_UNLOCK 0xF7 +#define STMFTS_FLASH_WRITE_64K 0xF8 +#define STMFTS_FLASH_STATUS 0xF9 +#define STMFTS_FLASH_OP 0xFA #define STMFTS_UNK5 0x62 +/* cmd parameters */ +#define STMFTS_VENDOR_GPIO_STATE 0x01 +#define STMFTS_VENDOR_SENSE_MODE 0x02 +#define STMFTS_STYLUS_MODE 0x00 +#define STMFTS_FINGER_MODE 0x01 +#define STMFTS_HOVER_MODE 0x02 /* events */ #define STMFTS_EV_NO_EVENT 0x00 @@ -74,6 +81,7 @@ #define STMFTS_EV_ERROR 0x0f #define STMFTS_EV_NOISE_READ 0x17 #define STMFTS_EV_NOISE_WRITE 0x18 +#define STMFTS_EV_VENDOR 0x20 #define STMFTS_EV_CONTROLLER_READY 0x10 #define STMFTS_EV_STATUS 0x16 @@ -131,6 +139,15 @@ typedef struct _touch_event { bool touch; } touch_event; +typedef struct _touch_panel_info_t +{ + u8 idx; + u8 gpio0; + u8 gpio1; + u8 gpio2; + char *vendor; +} touch_panel_info_t; + typedef struct _touch_info { u16 chip_id; u16 fw_ver; @@ -146,6 +163,7 @@ typedef struct _touch_fw_info_t { void touch_poll(touch_event *event); touch_event touch_poll_wait(); +touch_panel_info_t *touch_get_panel_vendor(); int touch_get_fw_info(touch_fw_info_t *fw); touch_info touch_get_info(); int touch_panel_ito_test(u8 *err); diff --git a/bdk/libs/compr/lz4.c b/bdk/libs/compr/lz4.c index ddea3d8..4f6f425 100644 --- a/bdk/libs/compr/lz4.c +++ b/bdk/libs/compr/lz4.c @@ -839,10 +839,12 @@ int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { int result; - LZ4_stream_t ctx; - LZ4_stream_t* const ctxPtr = &ctx; + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_stream_t* const ctxPtr = ctx; result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + FREEMEM(ctx); + return result; } @@ -857,13 +859,18 @@ int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxO /* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t ctx; - LZ4_resetStream(&ctx); + int result; + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_resetStream(ctx); if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); else - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); + result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); + + FREEMEM(ctx); + + return result; } @@ -1045,11 +1052,13 @@ static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { - LZ4_stream_t ctxBody; - LZ4_stream_t* ctx = &ctxBody; + LZ4_stream_t* ctxBody = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));; + LZ4_stream_t* ctx = ctxBody; int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + FREEMEM(ctxBody); + return result; } diff --git a/bdk/libs/fatfs/diskio.h b/bdk/libs/fatfs/diskio.h index 6959fb4..b5299c6 100644 --- a/bdk/libs/fatfs/diskio.h +++ b/bdk/libs/fatfs/diskio.h @@ -27,7 +27,8 @@ typedef enum { DRIVE_SD = 0, DRIVE_RAM = 1, DRIVE_EMMC = 2, - DRIVE_BIS = 3 + DRIVE_BIS = 3, + DRIVE_EMU = 4 } DDRIVE; @@ -59,6 +60,7 @@ DRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff); #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ +#define SET_SECTOR_OFFSET 5 /* Set media logical offset */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ diff --git a/bdk/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c index 9035f35..75e0271 100644 --- a/bdk/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 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, @@ -38,6 +38,7 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ +#include #include #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); @@ -3284,6 +3285,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ + fs->part_type = 0; /* Clear the Partition object */ fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ @@ -3318,6 +3320,20 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ EFSPRINTF("BRNL"); return FR_DISK_ERR; /* An error occured in the disk I/O layer */ } +#if FF_SIMPLE_GPT + if (fmt >= 2) { + /* If GPT Check the first partition */ + gpt_header_t *gpt_header = (gpt_header_t *)fs->win; + if (move_window(fs, 1) != FR_OK) return FR_DISK_ERR; + if (!mem_cmp(&gpt_header->signature, "EFI PART", 8)) { + if (move_window(fs, gpt_header->part_ent_lba) != FR_OK) return FR_DISK_ERR; + gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win; + fs->part_type = 1; + bsect = gpt_entry->lba_start; + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } + } +#endif if (fmt >= 2) { EFSPRINTF("NOFAT"); return FR_NO_FILESYSTEM; /* No FAT volume is found */ @@ -6169,7 +6185,9 @@ FRESULT f_mkfs ( #endif /* Create FAT VBR */ mem_set(buf, 0, ss); - mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + /* Boot jump code (x86), OEM name */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "NYX1.0.0", 11); + else mem_cpy(buf + BS_JmpBoot, "\xEB\xE9\x90\x00\x00\x00\x00\x00\x00\x00\x00", 11); st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ @@ -6182,23 +6200,27 @@ FRESULT f_mkfs ( } buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ - st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_word(buf + BPB_NumHeads, (opt & FM_PRF2) ? 16 : 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ if (fmt == FS_FAT32) { - st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BS_VolID32, (opt & FM_PRF2) ? 0 : GET_FATTIME()); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */ + /* Volume label, FAT signature */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab32, FF_MKFS_LABEL "FAT32 ", 19); + else mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */ + /* Volume label, FAT signature */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab, FF_MKFS_LABEL "FAT ", 19); + else mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ @@ -6216,6 +6238,16 @@ FRESULT f_mkfs ( disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } + /* Create PRF2SAFE info */ + if (fmt == FS_FAT32 && opt & FM_PRF2) { + mem_set(buf, 0, ss); + buf[16] = 0x64; /* Record type */ + st_dword(buf + 32, 0x03); /* Unknown. SYSTEM: 0x3F00. USER: 0x03. Volatile. */ + st_dword(buf + 36, 25); /* Entries. SYSTEM: 22. USER: 25.Static? */ + st_dword(buf + 508, 0x517BBFE0); /* Custom CRC32. SYSTEM: 0x6B673904. USER: 0x517BBFE0. */ + disk_write(pdrv, buf, b_vol + 3, 1); /* Write PRF2SAFE info (VBR + 3) */ + } + /* Initialize FAT area */ mem_set(buf, 0, (UINT)szb_buf); sect = b_fat; /* FAT start sector */ diff --git a/bdk/libs/fatfs/ff.h b/bdk/libs/fatfs/ff.h index a83cf63..f8e3475 100644 --- a/bdk/libs/fatfs/ff.h +++ b/bdk/libs/fatfs/ff.h @@ -97,6 +97,7 @@ typedef DWORD FSIZE_t; typedef struct { BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE part_type; /* Partition type (0:MBR, 1:GPT) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ @@ -168,9 +169,6 @@ typedef struct { /* File object structure (FIL) */ typedef struct { -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ @@ -184,6 +182,9 @@ typedef struct { #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS] __attribute__((aligned(8))); /* File private data read/write window. DMA aligned. */ +#endif } FIL; @@ -365,6 +366,7 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define FM_EXFAT 0x04 #define FM_ANY 0x07 #define FM_SFD 0x08 +#define FM_PRF2 0x10 /* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 diff --git a/bdk/libs/lv_conf.h b/bdk/libs/lv_conf.h index dcc437d..7af36a4 100644 --- a/bdk/libs/lv_conf.h +++ b/bdk/libs/lv_conf.h @@ -155,7 +155,7 @@ /*Log settings*/ -#ifdef DEBUG_UART_PORT +#ifdef DEBUG_UART_LV_LOG # define USE_LV_LOG 1 /*Enable/disable the log module*/ #else # define USE_LV_LOG 0 /*Enable/disable the log module*/ diff --git a/bdk/libs/lvgl/lv_misc/lv_log.c b/bdk/libs/lvgl/lv_misc/lv_log.c index d2db0c7..9cd3d49 100644 --- a/bdk/libs/lvgl/lv_misc/lv_log.c +++ b/bdk/libs/lvgl/lv_misc/lv_log.c @@ -63,7 +63,7 @@ void lv_log_add(lv_log_level_t level, const char * file, int line, const char * if(level >= LV_LOG_LEVEL) { -#if LV_LOG_PRINTF +#if LV_LOG_PRINTF && defined(DEBUG_UART_PORT) static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; char *log = (char *)malloc(0x1000); s_printf(log, "%s: %s \t(%s #%d)\r\n", lvl_prefix[level], dsc, file, line); diff --git a/bdk/mem/mc.c b/bdk/mem/mc.c index cc136dc..4db3a30 100644 --- a/bdk/mem/mc.c +++ b/bdk/mem/mc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-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, @@ -20,6 +20,8 @@ #include #include +#define CONFIG_ENABLE_AHB_REDIRECT + void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock) { MC(MC_SEC_CARVEOUT_BOM) = bom; @@ -143,17 +145,19 @@ void mc_disable_ahb_redirect() void mc_enable() { + // Reset EMC source to PLLP. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; // Enable memory clocks. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & ~BIT(CLK_H_EMC)) | BIT(CLK_H_EMC); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & ~BIT(CLK_H_MEM)) | BIT(CLK_H_MEM); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & ~BIT(CLK_X_EMC_DLL)) | BIT(CLK_X_EMC_DLL); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MEM); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); // Clear clock resets for memory. CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); usleep(5); - //#ifdef CONFIG_ENABLE_AHB_REDIRECT +#ifdef CONFIG_ENABLE_AHB_REDIRECT + mc_enable_ahb_redirect(); +#else mc_disable_ahb_redirect(); - //mc_enable_ahb_redirect(); - //#endif +#endif } diff --git a/bdk/mem/minerva.c b/bdk/mem/minerva.c index 183b633..2560dfe 100644 --- a/bdk/mem/minerva.c +++ b/bdk/mem/minerva.c @@ -60,7 +60,7 @@ u32 minerva_init() mtc_config_t mtc_tmp; mtc_tmp.mtc_table = mtc_cfg->mtc_table; - mtc_tmp.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_tmp.sdram_id = fuse_read_dramid(false); mtc_tmp.init_done = MTC_NEW_MAGIC; u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp); @@ -81,7 +81,7 @@ u32 minerva_init() // Set table to nyx storage. 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_dramid(false); mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); @@ -104,21 +104,21 @@ u32 minerva_init() } mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; - mtc_cfg->rate_to = 204000; + mtc_cfg->rate_to = FREQ_204; mtc_cfg->train_mode = OP_TRAIN; minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 800000; + mtc_cfg->rate_to = FREQ_800; minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 1600000; + mtc_cfg->rate_to = FREQ_1600; minerva_cfg(mtc_cfg, NULL); // FSP WAR. mtc_cfg->train_mode = OP_SWITCH; - mtc_cfg->rate_to = 800000; + mtc_cfg->rate_to = FREQ_800; minerva_cfg(mtc_cfg, NULL); // Switch to max. - mtc_cfg->rate_to = 1600000; + mtc_cfg->rate_to = FREQ_1600; minerva_cfg(mtc_cfg, NULL); return 0; @@ -129,6 +129,7 @@ void minerva_change_freq(minerva_freq_t freq) if (!minerva_cfg) return; + // Check if requested frequency is different. Do not allow otherwise because it will hang. mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; if (mtc_cfg->rate_from != freq) { @@ -138,6 +139,23 @@ void minerva_change_freq(minerva_freq_t freq) } } +void minerva_prep_boot_freq() +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + // Check if there's RAM OC. If not exit. + if (mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600) + return; + + // FSP WAR. + minerva_change_freq(FREQ_204); + // Scale down to 800 MHz boot freq. + minerva_change_freq(FREQ_800); +} + void minerva_periodic_training() { if (!minerva_cfg) diff --git a/bdk/mem/minerva.h b/bdk/mem/minerva.h index ed80b95..51cb215 100644 --- a/bdk/mem/minerva.h +++ b/bdk/mem/minerva.h @@ -60,6 +60,7 @@ typedef enum extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); u32 minerva_init(); void minerva_change_freq(minerva_freq_t freq); +void minerva_prep_boot_freq(); void minerva_periodic_training(); #endif diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c index aad98db..b119f46 100644 --- a/bdk/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -54,11 +54,6 @@ typedef struct _sdram_vendor_patch_t #include "sdram_config_t210b01.inl" -static u32 _sdram_get_id() -{ - return ((fuse_read_odm(4) & 0xF8) >> 3); -} - static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) { bool err = true; @@ -1374,9 +1369,7 @@ static void _sdram_patch_model_params_t210b01(u32 dramid, u32 *params) static void *_sdram_get_params_t210() { // Check if id is proper. - u32 dramid = _sdram_get_id(); - if (dramid > 6) - dramid = 0; + u32 dramid = fuse_read_dramid(false); #ifdef CONFIG_SDRAM_COMPRESS_CFG @@ -1413,9 +1406,7 @@ static void *_sdram_get_params_t210() void *sdram_get_params_t210b01() { // Check if id is proper. - u32 dramid = _sdram_get_id(); - if (dramid > 27) - dramid = 8; + u32 dramid = fuse_read_dramid(false); u32 *buf = (u32 *)SDRAM_PARAMS_ADDR; memcpy(buf, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t)); @@ -1439,12 +1430,12 @@ void *sdram_get_params_t210b01() case LPDDR4X_HOAG_4GB_SAMSUNG_1Y_X: case LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y: case LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y: - case LPDDR4X_SDS_4GB_SAMSUNG_1Y_A: - case LPDDR4X_SDS_8GB_SAMSUNG_1Y_X: - case LPDDR4X_SDS_4GB_SAMSUNG_1Y_X: + case LPDDR4X_AULA_4GB_SAMSUNG_1Y_A: + case LPDDR4X_AULA_8GB_SAMSUNG_1Y_X: + case LPDDR4X_AULA_4GB_SAMSUNG_1Y_X: case LPDDR4X_IOWA_4GB_MICRON_1Y_A: case LPDDR4X_HOAG_4GB_MICRON_1Y_A: - case LPDDR4X_SDS_4GB_MICRON_1Y_A: + case LPDDR4X_AULA_4GB_MICRON_1Y_A: _sdram_patch_model_params_t210b01(dramid, (u32 *)buf); break; } @@ -1494,7 +1485,7 @@ static void _sdram_init_t210() const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210(); // Set DRAM voltage. - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); + max7762x_regulator_set_voltage(REGULATOR_SD1, 1100000); // VDDP Select. PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; @@ -1539,8 +1530,8 @@ static void _sdram_init_t210b01() void sdram_init() { - // Configure SD regulator for DRAM. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); + // Disable remote sense for SD1. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0 | MAX77620_SD_CNF2_RSVD); if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) _sdram_init_t210(); diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h index 77db819..8455862 100644 --- a/bdk/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -45,7 +45,7 @@ enum sdram_ids_erista LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, - LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, + LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, // Changed to AULA Hynix 4GB 1Y-A. LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 5, LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT = 6, @@ -76,14 +76,14 @@ enum sdram_ids_mariko LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y = 20, LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y = 21, - LPDDR4X_SDS_4GB_SAMSUNG_1Y_A = 22, + LPDDR4X_AULA_4GB_SAMSUNG_1Y_A = 22, - LPDDR4X_SDS_8GB_SAMSUNG_1Y_X = 23, - LPDDR4X_SDS_4GB_SAMSUNG_1Y_X = 24, + LPDDR4X_AULA_8GB_SAMSUNG_1Y_X = 23, + LPDDR4X_AULA_4GB_SAMSUNG_1Y_X = 24, LPDDR4X_IOWA_4GB_MICRON_1Y_A = 25, LPDDR4X_HOAG_4GB_MICRON_1Y_A = 26, - LPDDR4X_SDS_4GB_MICRON_1Y_A = 27 + LPDDR4X_AULA_4GB_MICRON_1Y_A = 27 }; void sdram_init(); diff --git a/bdk/mem/sdram_config.inl b/bdk/mem/sdram_config.inl index 727ec60..97c723a 100644 --- a/bdk/mem/sdram_config.inl +++ b/bdk/mem/sdram_config.inl @@ -97,7 +97,7 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { * DRAM size information * Specifies the value for EMC_ADR_CFG */ - .emc_adr_cfg = 0x00000001, // 2 populated DRAM Devices. + .emc_adr_cfg = 0x00000001, // 2 Ranks. /* * Specifies the time to wait after asserting pin @@ -243,7 +243,7 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { .emc_cfg_dig_dll = 0x002C00A0, .emc_cfg_dig_dll_1 = 0x00003701, .emc_cfg_dig_dll_period = 0x00008000, - .emc_dev_select = 0x00000000, // Both devices. + .emc_dev_select = 0x00000000, // Both Ranks. .emc_sel_dpd_ctrl = 0x00040008, /* Pads trimmer delays */ @@ -406,7 +406,7 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { .pmc_ddr_ctrl = 0x0007FF8B, .emc_acpd_control = 0x00000000, - .emc_swizzle_rank0_byte0 = 0x76543201, + .emc_swizzle_rank0_byte0 = 0x76543201, // Overridden to 0x76543201 by spare6/7. .emc_swizzle_rank0_byte1 = 0x65324710, .emc_swizzle_rank0_byte2 = 0x25763410, .emc_swizzle_rank0_byte3 = 0x25673401, @@ -454,7 +454,7 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { .emc_pmacro_data_rx_term_mode = 0x00000010, .emc_pmacro_cmd_rx_term_mode = 0x00003000, .emc_pmacro_data_pad_tx_ctrl = 0x02000111, - .emc_pmacro_common_pad_tx_ctrl = 0x00000008, + .emc_pmacro_common_pad_tx_ctrl = 0x00000008, // Overridden to 0x0000000A by spare4/5. .emc_pmacro_cmd_pad_tx_ctrl = 0x0A000000, .emc_cfg3 = 0x00000040, @@ -490,9 +490,9 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { .emc_pmacro_cmd_ctrl2 = 0x0A0A0A0A, /* DRAM size information */ - .mc_emem_adr_cfg = 0x00000001, // 2 populated DRAM Devices. - .mc_emem_adr_cfg_dev0 = 0x00070302, // Density 512MB. - .mc_emem_adr_cfg_dev1 = 0x00070302, // Density 512MB. + .mc_emem_adr_cfg = 0x00000001, // 2 Ranks. + .mc_emem_adr_cfg_dev0 = 0x00070302, // Rank 0 Density 512MB. + .mc_emem_adr_cfg_dev1 = 0x00070302, // Rank 1 Density 512MB. .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, .mc_emem_adr_cfg_bank_mask1 = 0x39722800, @@ -653,8 +653,8 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = { { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. // Samsung 6GB density config. - { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB sub-partition density. - { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB sub-partition density. + { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB Rank 0 density. + { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB Rank 1 density. { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. #ifdef CONFIG_SDRAM_COPPER_SUPPORT diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl index 983c93a..e5c197e 100644 --- a/bdk/mem/sdram_config_t210b01.inl +++ b/bdk/mem/sdram_config_t210b01.inl @@ -122,7 +122,7 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { * DRAM size information * Specifies the value for EMC_ADR_CFG */ - .emc_adr_cfg = 0x00000000, // 1 populated DRAM Device. + .emc_adr_cfg = 0x00000000, // 1 Rank. /* * Specifies the time to wait after asserting pin @@ -273,7 +273,7 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { .emc_cfg_dig_dll = 0x002C00A0, .emc_cfg_dig_dll_1 = 0x000F3701, .emc_cfg_dig_dll_period = 0x00008000, - .emc_dev_select = 0x00000002, // Dev0 only. + .emc_dev_select = 0x00000002, // Rank 0 only. .emc_sel_dpd_ctrl = 0x0004000C, /* Pads trimmer delays */ @@ -543,9 +543,9 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { .emc_pmacro_cmd_ctrl2 = 0x00000000, /* DRAM size information */ - .mc_emem_adr_cfg = 0x00000000, // 1 populated DRAM Device. - .mc_emem_adr_cfg_dev0 = 0x00080302, // Density 1024MB. - .mc_emem_adr_cfg_dev1 = 0x00080302, // Density 1024MB. + .mc_emem_adr_cfg = 0x00000000, // 1 Rank. + .mc_emem_adr_cfg_dev0 = 0x00080302, // Rank 0 Density 1024MB. + .mc_emem_adr_cfg_dev1 = 0x00080302, // Rank 1 Density 1024MB. .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, .mc_emem_adr_cfg_bank_mask1 = 0x39722800, @@ -733,7 +733,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ for SDEV Iowa and Hoag. { 0x05500000, 0x0D4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x134 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_adr_cfg. 2 Ranks. { 0x00000006, 0x1CC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse. { 0x00000005, 0x1D0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse_width. { 0x00000003, 0x1DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_einput. @@ -764,7 +764,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x40000001, 0x45C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_zcal_init_dev1. { 0x00000000, 0x594 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd4. { 0x00001000, 0x598 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x630 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_adr_cfg. 2 Ranks. { 0x00002000, 0x64C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_cfg. 8GB total density. { 0x00000002, 0x680 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_timing_r2r. { 0x02020001, 0x694 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_da_turns. @@ -810,7 +810,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x2A800000, 0x6DC / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override0. { 0x00000002, 0x6E0 / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB 10nm-class (1y) Die-X for Iowa, Hoag and SDS. + // Samsung LPDDR4X 4GB 10nm-class (1y) Die-X for Iowa, Hoag and Aula. { 0x05500000, 0x0D4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_vref_sel0. { 0x00000006, 0x1CC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_quse. @@ -822,10 +822,10 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x2A800000, 0x6DC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override0. { 0x00000002, 0x6E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 8GB 10nm-class (1y) Die-X for SDEV Iowa and SDS. + // Samsung LPDDR4X 8GB 10nm-class (1y) Die-X for SDEV Iowa and Aula. { 0x05500000, 0x0D4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x134 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_adr_cfg. 2 Ranks. { 0x00000006, 0x1CC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse. { 0x00000005, 0x1D0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse_width. { 0x00000003, 0x1DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_einput. @@ -847,7 +847,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x40000001, 0x45C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_zcal_init_dev1. { 0x00000000, 0x594 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd4. { 0x00001000, 0x598 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x630 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_adr_cfg. 2 Ranks. { 0x00002000, 0x64C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_cfg. 8GB total density. { 0x00000001, 0x670 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_faw. { 0x00000002, 0x680 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_r2r. @@ -881,7 +881,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { // Samsung LPDDR4X 8GB 10nm-class (1y) Die-Y for SDEV Iowa. { 0x05500000, 0x0D4 / 4, DRAM_ID2(21) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(21) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(21) }, // emc_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x134 / 4, DRAM_ID2(21) }, // emc_adr_cfg. 2 Ranks. { 0x00000008, 0x24C / 4, DRAM_ID2(21) }, // emc_tfaw. { 0x08010004, 0x2B8 / 4, DRAM_ID2(21) }, // emc_mrw1. { 0x08020000, 0x2BC / 4, DRAM_ID2(21) }, // emc_mrw2. @@ -914,7 +914,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x40000001, 0x45C / 4, DRAM_ID2(21) }, // emc_zcal_init_dev1. { 0x00000000, 0x594 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd4. { 0x00001000, 0x598 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(21) }, // mc_emem_adr_cfg. 2 populated DRAM Devices. + { 0x00000001, 0x630 / 4, DRAM_ID2(21) }, // mc_emem_adr_cfg. 2 Ranks. { 0x00002000, 0x64C / 4, DRAM_ID2(21) }, // mc_emem_cfg. 8GB total density. { 0x00000001, 0x670 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_faw. { 0x00000002, 0x680 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_r2r. @@ -922,7 +922,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x2A800000, 0x6DC / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override0. { 0x00000002, 0x6E0 / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown SDS. + // Samsung LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Aula. { 0x05500000, 0x0D4 / 4, DRAM_ID2(22) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(22) }, // emc_auto_cal_vref_sel0. { 0x00000008, 0x24C / 4, DRAM_ID2(22) }, // emc_tfaw. @@ -986,7 +986,7 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x00000002, 0x6E0 / 4, DRAM_ID2(22) }, // mc_video_protect_gpu_override1. { 0x0000009C, 0x814 / 4, DRAM_ID2(22) }, // swizzle_rank_byte_encode. - // Micron LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Iowa/Hoag/SDS. + // Micron LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Iowa/Hoag/Aula. { 0x05500000, 0x0D4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_config2. { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_vref_sel0. { 0x00000006, 0x1CC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_quse. diff --git a/bdk/memory_map.h b/bdk/memory_map.h index f72a0c5..d0bfd7b 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 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, @@ -49,8 +49,14 @@ // Virtual disk / Chainloader buffers. #define RAM_DISK_ADDR 0xA4000000 -#define NX_BIS_CACHE_ADDR RAM_DISK_ADDR #define RAM_DISK_SZ 0x41000000 // 1040MB. +#define RAM_DISK2_SZ 0x21000000 // 528MB. + +// NX BIS driver sector cache. +#define NX_BIS_CACHE_ADDR 0xC5000000 +#define NX_BIS_CACHE_SZ 0x10020000 // 256MB. +#define NX_BIS_LOOKUP_ADDR 0xD6000000 +#define NX_BIS_LOOKUP_SZ 0xF000000 // 240MB. // L4T Kernel Panic Storage (PSTORE). #define PSTORE_ADDR 0xB0000000 @@ -91,15 +97,10 @@ #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define DRAM_MEM_HOLE_ADR 0xF6A00000 -#define NX_BIS_LOOKUP_ADR DRAM_MEM_HOLE_ADR #define DRAM_MEM_HOLE_SZ 0x8140000 /* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */ #define DRAM_START2 0xFEB40000 -// NX BIS driver sector cache. -// #define NX_BIS_CACHE_ADDR 0xFEE00000 -// #define NX_BIS_CACHE_SZ 0x100000 - // USB buffers. #define USBD_ADDR 0xFEF00000 #define USB_DESCRIPTOR_ADDR 0xFEF40000 diff --git a/bdk/module.h b/bdk/module.h index 6ec303f..acc048c 100644 --- a/bdk/module.h +++ b/bdk/module.h @@ -21,10 +21,13 @@ #include #include +#define IANOS_EXT0 0x304E4149 + // Module Callback typedef void (*cbMainModule_t)(const char *s); typedef void (*memcpy_t)(void *, void *, size_t); typedef void (*memset_t)(void *, int, size_t); +typedef int (*reg_voltage_set_t)(u32, u32); typedef struct _bdkParams_t { @@ -33,6 +36,8 @@ typedef struct _bdkParams_t heap_t *sharedHeap; memcpy_t memcpy; memset_t memset; + u32 extension_magic; + reg_voltage_set_t reg_voltage_set; } *bdkParams_t; // Module Entrypoint diff --git a/bdk/power/max77620.h b/bdk/power/max77620.h index 23ee299..d54909f 100644 --- a/bdk/power/max77620.h +++ b/bdk/power/max77620.h @@ -1,8 +1,7 @@ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * - * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2019 CTCaer + * 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, @@ -30,24 +29,33 @@ #define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) #define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) #define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) -#define MAX77620_CNFGGLBL1_LBHYST (BIT(5) | BIT(4)) #define MAX77620_CNFGGLBL1_MPPLD BIT(6) #define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7) #define MAX77620_REG_CNFGGLBL2 0x01 -#define MAX77620_REG_CNFGGLBL3 0x02 -#define MAX77620_WDTC_MASK 0x3 -#define MAX77620_WDTEN BIT(2) -#define MAX77620_WDTSLPC BIT(3) -#define MAX77620_WDTOFFC BIT(4) #define MAX77620_TWD_MASK 0x3 #define MAX77620_TWD_2s 0x0 #define MAX77620_TWD_16s 0x1 #define MAX77620_TWD_64s 0x2 #define MAX77620_TWD_128s 0x3 +#define MAX77620_WDTEN BIT(2) +#define MAX77620_WDTSLPC BIT(3) +#define MAX77620_WDTOFFC BIT(4) +#define MAX77620_GLBL_LPM BIT(5) +#define MAX77620_I2CTWD_MASK 0xC0 +#define MAX77620_I2CTWD_DISABLED 0x00 +#define MAX77620_I2CTWD_1_33ms 0x40 +#define MAX77620_I2CTWD_35_7ms 0x80 +#define MAX77620_I2CTWD_41_7ms 0xC0 + +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_WDTC_MASK 0x3 #define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_CNFG1_PWR_MD_32K_MASK 0x3 #define MAX77620_CNFG1_32K_OUT0_EN BIT(2) +#define MAX77620_CNFG1_32KLOAD_MASK 0x30 +#define MAX77620_CNFG1_32K_OK BIT(7) #define MAX77620_REG_CNFGBBC 0x04 #define MAX77620_CNFGBBC_ENABLE BIT(0) @@ -64,6 +72,7 @@ #define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_REG_IRQTOPM 0x0D #define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1) #define MAX77620_IRQ_TOP_32K_MASK BIT(2) #define MAX77620_IRQ_TOP_RTC_MASK BIT(3) @@ -73,28 +82,53 @@ #define MAX77620_IRQ_TOP_GLBL_MASK BIT(7) #define MAX77620_REG_INTLBT 0x06 -#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_IRQ_GLBLM_MASK BIT(0) #define MAX77620_IRQ_TJALRM2_MASK BIT(1) #define MAX77620_IRQ_TJALRM1_MASK BIT(2) #define MAX77620_IRQ_LBM_MASK BIT(3) #define MAX77620_REG_IRQSD 0x07 -#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 -#define MAX77620_REG_IRQ_LVL2_L8 0x09 -#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A -#define MAX77620_REG_ONOFFIRQ 0x0B -#define MAX77620_REG_NVERC 0x0C - -#define MAX77620_REG_INTENLBT 0x0E -#define MAX77620_GLBLM_MASK BIT(0) - #define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_IRQSD_PFI_SD3 BIT(4) +#define MAX77620_IRQSD_PFI_SD2 BIT(5) +#define MAX77620_IRQSD_PFI_SD1 BIT(6) +#define MAX77620_IRQSD_PFI_SD0 BIT(7) + +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 // LDO number that irq occured. #define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 // LDO number that irq occured. Only bit0: LDO8 is valid. #define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A // Edge detection interrupt. + +#define MAX77620_REG_ONOFFIRQ 0x0B #define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_ONOFFIRQ_MRWRN BIT(0) +#define MAX77620_ONOFFIRQ_EN0_1SEC BIT(1) +#define MAX77620_ONOFFIRQ_EN0_F BIT(2) +#define MAX77620_ONOFFIRQ_EN0_R BIT(3) +#define MAX77620_ONOFFIRQ_LID_F BIT(4) +#define MAX77620_ONOFFIRQ_LID_R BIT(5) +#define MAX77620_ONOFFIRQ_ACOK_F BIT(6) +#define MAX77620_ONOFFIRQ_ACOK_R BIT(7) + +#define MAX77620_REG_NVERC 0x0C // Shutdown reason (non-volatile). +#define MAX77620_NVERC_SHDN BIT(0) +#define MAX77620_NVERC_WTCHDG BIT(1) +#define MAX77620_NVERC_HDRST BIT(2) +#define MAX77620_NVERC_TOVLD BIT(3) +#define MAX77620_NVERC_MBLSD BIT(4) +#define MAX77620_NVERC_MBO BIT(5) +#define MAX77620_NVERC_MBU BIT(6) +#define MAX77620_NVERC_RSTIN BIT(7) + #define MAX77620_REG_STATLBT 0x13 #define MAX77620_REG_STATSD 0x14 + #define MAX77620_REG_ONOFFSTAT 0x15 +#define MAX77620_ONOFFSTAT_LID BIT(0) +#define MAX77620_ONOFFSTAT_ACOK BIT(1) +#define MAX77620_ONOFFSTAT_EN0 BIT(2) /* SD and LDO Registers */ #define MAX77620_REG_SD0 0x16 @@ -102,18 +136,42 @@ #define MAX77620_REG_SD2 0x18 #define MAX77620_REG_SD3 0x19 #define MAX77620_REG_SD4 0x1A +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C #define MAX77620_SDX_VOLT_MASK 0xFF #define MAX77620_SD0_VOLT_MASK 0x3F #define MAX77620_SD1_VOLT_MASK 0x7F #define MAX77620_LDO_VOLT_MASK 0x3F -#define MAX77620_REG_DVSSD0 0x1B -#define MAX77620_REG_DVSSD1 0x1C -#define MAX77620_REG_SD0_CFG 0x1D // SD CNFG1. -#define MAX77620_REG_SD1_CFG 0x1E // SD CNFG1. -#define MAX77620_REG_SD2_CFG 0x1F // SD CNFG1. -#define MAX77620_REG_SD3_CFG 0x20 // SD CNFG1. -#define MAX77620_REG_SD4_CFG 0x21 // SD CNFG1. + +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK BIT(3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) +#define MAX77620_SD_CFG1_MPOK_MASK BIT(1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) + #define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_SD_CNF2_RSVD BIT(0) +#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) + #define MAX77620_REG_LDO0_CFG 0x23 #define MAX77620_REG_LDO0_CFG2 0x24 #define MAX77620_REG_LDO1_CFG 0x25 @@ -132,26 +190,36 @@ #define MAX77620_REG_LDO7_CFG2 0x32 #define MAX77620_REG_LDO8_CFG 0x33 #define MAX77620_REG_LDO8_CFG2 0x34 -#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) -#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) -#define MAX77620_LDO_CFG2_SS_SLOW 0 -#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) -#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) -#define MAX20024_LDO_CFG2_MPOK_MASK BIT(2) -#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +/*! LDO CFG */ #define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_LDO_POWER_MODE_MASK (3 << MAX77620_LDO_POWER_MODE_SHIFT) #define MAX77620_POWER_MODE_NORMAL 3 #define MAX77620_POWER_MODE_LPM 2 #define MAX77620_POWER_MODE_GLPM 1 #define MAX77620_POWER_MODE_DISABLE 0 +/*! LDO CFG2 */ +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (0 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW (1 << 0) +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX77620_LDO_CFG2_MPOK_MASK BIT(2) +#define MAX77620_LDO_CFG2_POK_MASK BIT(3) +#define MAX77620_LDO_CFG2_COMP_SHIFT 4 +#define MAX77620_LDO_CFG2_COMP_MASK (3 << MAX77620_LDO_COMP_SHIFT) +#define MAX77620_LDO_CFG2_COMP_SLOW 3 +#define MAX77620_LDO_CFG2_COMP_MID_SLOW 2 +#define MAX77620_LDO_CFG2_COMP_MID_FAST 1 +#define MAX77620_LDO_CFG2_COMP_FAST 0 +#define MAX77620_LDO_CFG2_ALPM_EN_MASK BIT(6) +#define MAX77620_LDO_CFG2_OVCLMP_MASK BIT(7) #define MAX77620_REG_LDO_CFG3 0x35 +#define MAX77620_LDO_BIAS_EN BIT(0) #define MAX77620_TRACK4_SHIFT 5 #define MAX77620_TRACK4_MASK (1 << MAX77620_TRACK4_SHIFT) -#define MAX77620_LDO_SLEW_RATE_MASK 0x1 - #define MAX77620_REG_GPIO0 0x36 #define MAX77620_REG_GPIO1 0x37 #define MAX77620_REG_GPIO2 0x38 @@ -160,9 +228,6 @@ #define MAX77620_REG_GPIO5 0x3B #define MAX77620_REG_GPIO6 0x3C #define MAX77620_REG_GPIO7 0x3D -#define MAX77620_REG_PUE_GPIO 0x3E -#define MAX77620_REG_PDE_GPIO 0x3F -#define MAX77620_REG_AME_GPIO 0x40 #define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) #define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) #define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) @@ -181,6 +246,13 @@ #define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) #define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) #define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) +#define MAX77620_GPIO_OUTPUT_DISABLE 0 +#define MAX77620_GPIO_OUTPUT_ENABLE 1 + +#define MAX77620_REG_PUE_GPIO 0x3E // Gpio Pullup resistor enable. +#define MAX77620_REG_PDE_GPIO 0x3F // Gpio Pulldown resistor enable. + +#define MAX77620_REG_AME_GPIO 0x40 // Gpio pinmuxing. Clear bits are Standard GPIO. #define MAX77620_REG_ONOFFCNFG1 0x41 #define MAX20024_ONOFFCNFG1_CLRSE 0x18 @@ -188,19 +260,30 @@ #define MAX77620_ONOFFCNFG1_SLPEN BIT(2) #define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 #define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_RSVD BIT(6) #define MAX77620_ONOFFCNFG1_SFT_RST BIT(7) #define MAX77620_REG_ONOFFCNFG2 0x42 #define MAX77620_ONOFFCNFG2_WK_EN0 BIT(0) +#define MAX77620_ONOFFCNFG2_WK_ALARM2 BIT(1) #define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2) +#define MAX77620_ONOFFCNFG2_WK_MBATT BIT(3) // MBATT event generates a wakeup signal. use it in android/l4t? +#define MAX77620_ONOFFCNFG2_WK_ACOK BIT(4) #define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5) #define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6) #define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7) /* FPS Registers */ -#define MAX77620_REG_FPS_CFG0 0x43 -#define MAX77620_REG_FPS_CFG1 0x44 -#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_CFG0 0x43 // FPS0. +#define MAX77620_REG_FPS_CFG1 0x44 // FPS1. +#define MAX77620_REG_FPS_CFG2 0x45 // FPS2. +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 + #define MAX77620_REG_FPS_LDO0 0x46 #define MAX77620_REG_FPS_LDO1 0x47 #define MAX77620_REG_FPS_LDO2 0x48 @@ -215,77 +298,39 @@ #define MAX77620_REG_FPS_SD2 0x51 #define MAX77620_REG_FPS_SD3 0x52 #define MAX77620_REG_FPS_SD4 0x53 -#define MAX77620_REG_FPS_NONE 0 -#define MAX77620_FPS_SRC_MASK 0xC0 -#define MAX77620_FPS_SRC_SHIFT 6 -#define MAX77620_FPS_PU_PERIOD_MASK 0x38 -#define MAX77620_FPS_PU_PERIOD_SHIFT 3 -#define MAX77620_FPS_PD_PERIOD_MASK 0x07 -#define MAX77620_FPS_PD_PERIOD_SHIFT 0 - -/* Minimum and maximum FPS period time (in microseconds) are - * different for MAX77620 and Max20024. - */ -#define MAX77620_FPS_COUNT 3 - -#define MAX77620_FPS_PERIOD_MIN_US 40 -#define MAX20024_FPS_PERIOD_MIN_US 20 - -#define MAX77620_FPS_PERIOD_MAX_US 2560 -#define MAX20024_FPS_PERIOD_MAX_US 5120 - #define MAX77620_REG_FPS_GPIO1 0x54 #define MAX77620_REG_FPS_GPIO2 0x55 #define MAX77620_REG_FPS_GPIO3 0x56 -#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 -#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 -#define MAX77620_FPS_EN_SRC_MASK 0x06 -#define MAX77620_FPS_EN_SRC_SHIFT 1 -#define MAX77620_FPS_ENFPS_SW_MASK 0x01 -#define MAX77620_FPS_ENFPS_SW 0x01 - #define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_SRC_MASK 0xC0 + +#define MAX77620_FPS_COUNT 3 +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX77620_FPS_PERIOD_MAX_US 2560 + #define MAX77620_REG_CID0 0x58 #define MAX77620_REG_CID1 0x59 #define MAX77620_REG_CID2 0x5A #define MAX77620_REG_CID3 0x5B -#define MAX77620_REG_CID4 0x5C +#define MAX77620_REG_CID4 0x5C // OTP version. #define MAX77620_REG_CID5 0x5D - -#define MAX77620_REG_DVSSD4 0x5E -#define MAX20024_REG_MAX_ADD 0x70 - -#define MAX77620_CID_DIDM_MASK 0xF0 -#define MAX77620_CID_DIDM_SHIFT 4 - -/* CNCG2SD */ -#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) -#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) +#define MAX77620_CID_DIDO_MASK 0xF +#define MAX77620_CID_DIDO_SHIFT 0 +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 /* Device Identification Metal */ #define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) /* Device Indentification OTP */ #define MAX77620_CID5_DIDO(n) ((n) & 0xF) -/* SD CNFG1 */ -#define MAX77620_SD_SR_MASK 0xC0 -#define MAX77620_SD_SR_SHIFT 6 -#define MAX77620_SD_POWER_MODE_MASK 0x30 -#define MAX77620_SD_POWER_MODE_SHIFT 4 -#define MAX77620_SD_CFG1_ADE_MASK BIT(3) -#define MAX77620_SD_CFG1_ADE_DISABLE 0 -#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3) -#define MAX77620_SD_FPWM_MASK 0x04 -#define MAX77620_SD_FPWM_SHIFT 2 -#define MAX77620_SD_FSRADE_MASK 0x01 -#define MAX77620_SD_FSRADE_SHIFT 0 -#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2) -#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 -#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) -#define MAX20024_SD_CFG1_MPOK_MASK BIT(1) -#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) -#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 -#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 #define MAX77620_IRQ_LVL2_GPIO_EDGE0 BIT(0) #define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1) @@ -332,9 +377,4 @@ enum max77620_fps_src { MAX77620_FPS_SRC_DEF, }; -enum max77620_chip_id { - MAX77620, - MAX20024, -}; - #endif /* _MFD_MAX77620_H_ */ diff --git a/bdk/power/max7762x.c b/bdk/power/max7762x.c index c32cf76..a7d30ce 100644 --- a/bdk/power/max7762x.c +++ b/bdk/power/max7762x.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer + * 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, @@ -17,163 +17,323 @@ #include #include +#include +#include #include +#include #include -#define REGULATOR_SD 0 +#define REGULATOR_SD 0 #define REGULATOR_LDO 1 +#define REGULATOR_BC0 2 +#define REGULATOR_BC1 3 -typedef struct _max77620_regulator_t +typedef struct _max77620_fps_t { - u8 type; - const char *name; - u8 reg_sd; - - u32 mv_step; - u32 mv_min; - u32 mv_default; - u32 mv_max; - - u8 volt_addr; - u8 cfg_addr; - - u8 volt_mask; - u8 enable_mask; - u8 enable_shift; - u8 status_mask; - u8 fps_addr; u8 fps_src; u8 pd_period; u8 pu_period; +} max77620_fps_t; + +typedef struct _max77621_ctrl_t +{ + u8 ctrl1_por; + u8 ctrl1_hos; + u8 ctrl2_por; + u8 ctrl2_hos; +} max77621_ctrl_t; + +typedef struct _max77812_ctrl_t +{ + u8 mask; + u8 shift; + u8 rsvd0; + u8 rsvd1; +} max77812_en_t; + +typedef struct _max77620_regulator_t +{ + const char *name; + + u32 uv_step; + u32 uv_min; + u32 uv_default; + u32 uv_max; + + u8 type; + u8 volt_addr; + u8 cfg_addr; + u8 volt_mask; + + union { + max77620_fps_t fps; + max77621_ctrl_t ctrl; + max77812_en_t enable; + }; } max77620_regulator_t; static const max77620_regulator_t _pmic_regulators[] = { - { REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 }, - { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 }, - { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 }, - { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 }, - { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 }, - { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 }, - { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 }, - { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 }, - { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 }, - { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, - { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, - { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, - { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 2800000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } + { "sd0", 12500, 600000, 625000, 1400000, REGULATOR_SD, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, {{ MAX77620_REG_FPS_SD0, 1, 7, 1 }} }, + { "sd1", 12500, 600000, 1125000, 1250000, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} }, + { "sd2", 12500, 600000, 1325000, 1350000, REGULATOR_SD, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD2, 1, 5, 2 }} }, + { "sd3", 12500, 600000, 1800000, 1800000, REGULATOR_SD, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD3, 0, 3, 3 }} }, + { "ldo0", 25000, 800000, 1200000, 1200000, REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} }, + { "ldo1", 25000, 800000, 1050000, 1050000, REGULATOR_LDO, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO1, 3, 7, 0 }} }, + { "ldo2", 50000, 800000, 1800000, 3300000, REGULATOR_LDO, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO2, 3, 7, 0 }} }, + { "ldo3", 50000, 800000, 3100000, 3100000, REGULATOR_LDO, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO3, 3, 7, 0 }} }, + { "ldo4", 12500, 800000, 850000, 1000000, REGULATOR_LDO, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO4, 0, 7, 1 }} }, + { "ldo5", 50000, 800000, 1800000, 1800000, REGULATOR_LDO, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO5, 3, 7, 0 }} }, + { "ldo6", 50000, 800000, 2900000, 2900000, REGULATOR_LDO, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO6, 3, 7, 0 }} }, + { "ldo7", 50000, 800000, 1050000, 1050000, REGULATOR_LDO, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO7, 1, 4, 3 }} }, + { "ldo8", 50000, 800000, 1050000, 2800000, REGULATOR_LDO, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO8, 3, 7, 0 }} }, + + { "max77621_CPU", 6250, 606250, 1000000, 1400000, REGULATOR_BC0, MAX77621_VOUT_REG, MAX77621_VOUT_DVS_REG, MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} }, + { "max77621_GPU", 6250, 606250, 1200000, 1400000, REGULATOR_BC0, MAX77621_VOUT_REG, MAX77621_VOUT_DVS_REG, MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} }, + { "max77812_CPU", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M4_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M4_MASK, MAX77812_EN_CTRL_EN_M4_SHIFT, 0, 0 }} }, + //{ "max77812_GPU", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M1_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M1_MASK, MAX77812_EN_CTRL_EN_M1_SHIFT, 0, 0 }} }, + //{ "max77812_RAM", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M3_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M3_MASK, MAX77812_EN_CTRL_EN_M3_SHIFT, 0, 0 }} } // Only on PHASE211 configuration. }; -static void _max77620_set_reg(u8 reg, u8 val) +static u8 _max77812_get_address() +{ + static u8 max77812_i2c_addr = 0; + + if (max77812_i2c_addr) + return max77812_i2c_addr; + + max77812_i2c_addr = + !(FUSE(FUSE_RESERVED_ODM28_T210B01) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR; + + return max77812_i2c_addr; +} + +static u8 _max7762x_get_i2c_address(u32 id) +{ + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + // Choose the correct i2c address. + switch (reg->type) + { + case REGULATOR_SD: + case REGULATOR_LDO: + return MAX77620_I2C_ADDR; + case REGULATOR_BC0: + return (id == REGULATOR_CPU0 ? MAX77621_CPU_I2C_ADDR : MAX77621_GPU_I2C_ADDR); + case REGULATOR_BC1: + return _max77812_get_address(); + default: + return 0; + } +} + +static void _max7762x_set_reg(u8 addr, u8 reg, u8 val) { u32 retries = 100; while (retries) { - if (i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val)) + if (i2c_send_byte(I2C_5, addr, reg, val)) break; - usleep(100); + + usleep(50); retries--; } } int max77620_regulator_get_status(u32 id) { - if (id > REGULATOR_MAX) + if (id > REGULATOR_LDO8) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; + // SD power OK status. if (reg->type == REGULATOR_SD) - return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; - return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & 8) ? 1 : 0; + { + u8 mask = 1u << (7 - id); + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & mask) ? 0 : 1; + } + + // LDO power OK status. + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & MAX77620_LDO_CFG2_POK_MASK) ? 1 : 0; } int max77620_regulator_config_fps(u32 id) { - if (id > REGULATOR_MAX) + if (id > REGULATOR_LDO8) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; - _max77620_set_reg(reg->fps_addr, - (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); + // Set FPS configuration. + _max7762x_set_reg(MAX77620_I2C_ADDR, + reg->fps.fps_addr, + (reg->fps.fps_src << MAX77620_FPS_SRC_SHIFT) | + (reg->fps.pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | + (reg->fps.pd_period << MAX77620_FPS_PD_PERIOD_SHIFT)); return 1; } -int max77620_regulator_set_voltage(u32 id, u32 mv) +int max7762x_regulator_set_voltage(u32 id, u32 mv) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; - if (mv < reg->mv_min || mv > reg->mv_max) + if (mv < reg->uv_min || mv > reg->uv_max) return 0; - u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; - u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); + u8 addr = _max7762x_get_i2c_address(id); + + // Calculate voltage multiplier. + u32 mult = (mv + reg->uv_step - 1 - reg->uv_min) / reg->uv_step; + u8 val = i2c_recv_byte(I2C_5, addr, reg->volt_addr); val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_set_reg(reg->volt_addr, val); + + // Set voltage. + _max7762x_set_reg(addr, reg->volt_addr, val); + + // If max77621 set DVS voltage also. + if (reg->type == REGULATOR_BC0) + _max7762x_set_reg(addr, reg->cfg_addr, MAX77621_VOUT_ENABLE_MASK | val); + + // Wait for ramp up/down delay. usleep(1000); return 1; } -int max77620_regulator_enable(u32 id, int enable) +int max7762x_regulator_enable(u32 id, bool enable) { + u8 reg_addr; + u8 enable_val; + u8 enable_mask; + u8 enable_shift; + if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; - u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr; - u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr); + // Choose the correct i2c and register addresses and mask/shift for each type. + switch (reg->type) + { + case REGULATOR_SD: + reg_addr = reg->cfg_addr; + enable_val = MAX77620_POWER_MODE_NORMAL; + enable_mask = MAX77620_SD_POWER_MODE_MASK; + enable_shift = MAX77620_SD_POWER_MODE_SHIFT; + break; + case REGULATOR_LDO: + reg_addr = reg->volt_addr; + enable_val = MAX77620_POWER_MODE_NORMAL; + enable_mask = MAX77620_LDO_POWER_MODE_MASK; + enable_shift = MAX77620_LDO_POWER_MODE_SHIFT; + break; + case REGULATOR_BC0: + reg_addr = reg->volt_addr; + enable_val = MAX77621_VOUT_ENABLE; + enable_mask = MAX77621_DVC_DVS_ENABLE_MASK; + enable_shift = MAX77621_DVC_DVS_ENABLE_SHIFT; + break; + case REGULATOR_BC1: + reg_addr = reg->cfg_addr; + enable_val = MAX77812_EN_CTRL_ENABLE; + enable_mask = reg->enable.mask; + enable_shift = reg->enable.shift; + break; + default: + return 0; + } + + u8 addr = _max7762x_get_i2c_address(id); + + // Read and enable/disable. + u8 val = i2c_recv_byte(I2C_5, addr, reg_addr); + val &= ~enable_mask; + if (enable) - val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); - else - val &= ~reg->enable_mask; - _max77620_set_reg(addr, val); + val |= (enable_val << enable_shift); + + // Set enable. + _max7762x_set_reg(addr, reg_addr, val); + + // Wait for enable/disable ramp delay. usleep(1000); return 1; } -// LDO only. -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) +void max77620_config_gpio(u32 gpio_id, bool enable) { - if (id > REGULATOR_MAX) - return 0; + if (gpio_id > 7) + return; + // Configure as standard GPIO. + u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, val & ~BIT(gpio_id)); + + // Set GPIO configuration. + if (enable) + val = MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DIR_OUTPUT | MAX77620_CNFG_GPIO_DRV_PUSHPULL; + else + val = MAX77620_CNFG_GPIO_DIR_INPUT | MAX77620_CNFG_GPIO_DRV_OPENDRAIN; + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO0 + gpio_id, val); +} + +void max77621_config_default(u32 id, bool por) +{ const max77620_regulator_t *reg = &_pmic_regulators[id]; - if (mv < reg->mv_min || mv > reg->mv_max) - return 0; + if (reg->type != REGULATOR_BC0) + return; - u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; - u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_set_reg(reg->volt_addr, val); - usleep(1000); + u8 addr = _max7762x_get_i2c_address(id); - return 1; + if (por) + { + // Set voltage and disable power before changing the inductor. + max7762x_regulator_set_voltage(id, 1000000); + max7762x_regulator_enable(id, false); + + // Configure to default. + i2c_send_byte(I2C_5, addr, MAX77621_CONTROL1_REG, reg->ctrl.ctrl1_por); + i2c_send_byte(I2C_5, addr, MAX77621_CONTROL2_REG, reg->ctrl.ctrl2_por); + } + else + { + i2c_send_byte(I2C_5, addr, MAX77621_CONTROL1_REG, reg->ctrl.ctrl1_hos); + i2c_send_byte(I2C_5, addr, MAX77621_CONTROL2_REG, reg->ctrl.ctrl2_hos); + } } void max77620_config_default() { - for (u32 i = 1; i <= REGULATOR_MAX; i++) + // Check if Erista OTP. + if (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4) != 0x35) + return; + + // Set default voltages and enable regulators. + for (u32 i = 1; i <= REGULATOR_LDO8; i++) { - i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4); max77620_regulator_config_fps(i); - max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default); - if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) - max77620_regulator_enable(i, 1); + max7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default); + if (_pmic_regulators[i].fps.fps_src != MAX77620_FPS_SRC_NONE) + max7762x_regulator_enable(i, true); } - _max77620_set_reg(MAX77620_REG_SD_CFG2, 4); + + // Enable SD0 output voltage sense and disable for SD1. Additionally disable the reserved bit. + _max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0); } +// Stock HOS: disabled. void max77620_low_battery_monitor_config(bool enable) { - _max77620_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | - MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); + _max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1, + MAX77620_CNFGGLBL1_LBDAC_EN | + (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | + MAX77620_CNFGGLBL1_LBHYST_200 | + MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/bdk/power/max7762x.h b/bdk/power/max7762x.h index dd06bf7..3478530 100644 --- a/bdk/power/max7762x.h +++ b/bdk/power/max7762x.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer + * 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, @@ -32,11 +32,11 @@ * ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) -* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | +* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | 0.85V (AO, pcv) * ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) -* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V -* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | -* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | +* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V (pcv) +* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv) */ /* @@ -45,10 +45,10 @@ */ /*! MAX77620 partitions. */ -#define REGULATOR_SD0 0 -#define REGULATOR_SD1 1 -#define REGULATOR_SD2 2 -#define REGULATOR_SD3 3 +#define REGULATOR_SD0 0 +#define REGULATOR_SD1 1 +#define REGULATOR_SD2 2 +#define REGULATOR_SD3 3 #define REGULATOR_LDO0 4 #define REGULATOR_LDO1 5 #define REGULATOR_LDO2 6 @@ -58,26 +58,40 @@ #define REGULATOR_LDO6 10 #define REGULATOR_LDO7 11 #define REGULATOR_LDO8 12 -#define REGULATOR_MAX 12 +#define REGULATOR_CPU0 13 +#define REGULATOR_GPU0 14 +#define REGULATOR_CPU1 15 +//#define REGULATOR_GPU1 16 +//#define REGULATOR_GPU1 17 +#define REGULATOR_MAX 15 #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C -#define MAX77621_VOUT_REG 0 -#define MAX77621_VOUT_DVS_REG 1 -#define MAX77621_CONTROL1_REG 2 -#define MAX77621_CONTROL2_REG 3 - -/* MAX77621_VOUT */ -#define MAX77621_VOUT_ENABLE BIT(7) -#define MAX77621_VOUT_MASK 0x7F -#define MAX77621_VOUT_0_95V 0x37 -#define MAX77621_VOUT_1_09V 0x4F +#define MAX77621_VOUT_REG 0x00 +#define MAX77621_VOUT_DVS_REG 0x01 +#define MAX77621_CONTROL1_REG 0x02 +#define MAX77621_CONTROL2_REG 0x03 +#define MAX77621_CHIPID1_REG 0x04 +#define MAX77621_CHIPID2_REG 0x05 /* MAX77621_VOUT_DVC_DVS */ -#define MAX77621_DVS_VOUT_MASK 0x7F +#define MAX77621_DVC_DVS_VOLT_MASK 0x7F +#define MAX77621_DVC_DVS_ENABLE_SHIFT 7 +#define MAX77621_DVC_DVS_ENABLE_MASK (1 << MAX77621_DVC_DVS_ENABLE_SHIFT) + +/* MAX77621_VOUT */ +#define MAX77621_VOUT_DISABLE 0 +#define MAX77621_VOUT_ENABLE 1 +#define MAX77621_VOUT_ENABLE_MASK (MAX77621_VOUT_ENABLE << MAX77621_DVC_DVS_ENABLE_SHIFT) /* MAX77621_CONTROL1 */ +#define MAX77621_RAMP_12mV_PER_US 0x0 +#define MAX77621_RAMP_25mV_PER_US 0x1 +#define MAX77621_RAMP_50mV_PER_US 0x2 +#define MAX77621_RAMP_200mV_PER_US 0x3 +#define MAX77621_RAMP_MASK 0x3 + #define MAX77621_FREQSHIFT_9PER BIT(2) #define MAX77621_BIAS_ENABLE BIT(3) #define MAX77621_AD_ENABLE BIT(4) @@ -85,34 +99,50 @@ #define MAX77621_FPWM_EN_M BIT(6) #define MAX77621_SNS_ENABLE BIT(7) -#define MAX77621_RAMP_12mV_PER_US 0x0 -#define MAX77621_RAMP_25mV_PER_US 0x1 -#define MAX77621_RAMP_50mV_PER_US 0x2 -#define MAX77621_RAMP_200mV_PER_US 0x3 -#define MAX77621_RAMP_MASK 0x3 - /* MAX77621_CONTROL2 */ -#define MAX77621_FT_ENABLE BIT(4) -#define MAX77621_DISCH_ENBABLE BIT(5) -#define MAX77621_WDTMR_ENABLE BIT(6) -#define MAX77621_T_JUNCTION_120 BIT(7) +#define MAX77621_INDUCTOR_MIN_30_PER 0 +#define MAX77621_INDUCTOR_NOMINAL 1 +#define MAX77621_INDUCTOR_PLUS_30_PER 2 +#define MAX77621_INDUCTOR_PLUS_60_PER 3 +#define MAX77621_INDUCTOR_MASK 3 -#define MAX77621_CKKADV_TRIP_DISABLE 0xC #define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 -#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 -#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 +#define MAX77621_CKKADV_TRIP_150mV_PER_US BIT(2) +#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS BIT(3) +#define MAX77621_CKKADV_TRIP_DISABLE (BIT(2) | BIT(3)) +#define MAX77621_CKKADV_TRIP_MASK (BIT(2) | BIT(3)) -#define MAX77621_INDUCTOR_MIN_30_PER 0x0 -#define MAX77621_INDUCTOR_NOMINAL 0x1 -#define MAX77621_INDUCTOR_PLUS_30_PER 0x2 -#define MAX77621_INDUCTOR_PLUS_60_PER 0x3 +#define MAX77621_FT_ENABLE BIT(4) +#define MAX77621_DISCH_ENABLE BIT(5) +#define MAX77621_WDTMR_ENABLE BIT(6) +#define MAX77621_T_JUNCTION_120 BIT(7) -int max77620_regulator_get_status(u32 id); -int max77620_regulator_config_fps(u32 id); -int max77620_regulator_set_voltage(u32 id, u32 mv); -int max77620_regulator_enable(u32 id, int enable); -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); +#define MAX77621_CPU_CTRL1_POR_DEFAULT (MAX77621_RAMP_50mV_PER_US) +#define MAX77621_CPU_CTRL1_HOS_DEFAULT (MAX77621_AD_ENABLE | \ + MAX77621_NFSR_ENABLE | \ + MAX77621_SNS_ENABLE | \ + MAX77621_RAMP_12mV_PER_US) +#define MAX77621_CPU_CTRL2_POR_DEFAULT (MAX77621_T_JUNCTION_120 | \ + MAX77621_FT_ENABLE | \ + MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | \ + MAX77621_CKKADV_TRIP_150mV_PER_US | \ + MAX77621_INDUCTOR_NOMINAL) +#define MAX77621_CPU_CTRL2_HOS_DEFAULT (MAX77621_T_JUNCTION_120 | \ + MAX77621_WDTMR_ENABLE | \ + MAX77621_CKKADV_TRIP_75mV_PER_US | \ + MAX77621_INDUCTOR_NOMINAL) + +#define MAX77621_CTRL_HOS_CFG 0 +#define MAX77621_CTRL_POR_CFG 1 + +int max77620_regulator_get_status(u32 id); +int max77620_regulator_config_fps(u32 id); +int max7762x_regulator_set_voltage(u32 id, u32 mv); +int max7762x_regulator_enable(u32 id, bool enable); +void max77620_config_gpio(u32 id, bool enable); void max77620_config_default(); void max77620_low_battery_monitor_config(bool enable); +void max77621_config_default(u32 id, bool por); + #endif diff --git a/bdk/power/max77812.h b/bdk/power/max77812.h index f8ac3fb..89c3baf 100644 --- a/bdk/power/max77812.h +++ b/bdk/power/max77812.h @@ -17,8 +17,8 @@ #ifndef _MAX77812_H_ #define _MAX77812_H_ -#define MAX77812_PHASE31_CPU_I2C_ADDR 0x31 -#define MAX77812_PHASE211_CPU_I2C_ADDR 0x33 +#define MAX77812_PHASE31_CPU_I2C_ADDR 0x31 // 2 Outputs: 3-phase M1 + 1-phase M4. +#define MAX77812_PHASE211_CPU_I2C_ADDR 0x33 // 3 Outputs: 2-phase M1 + 1-phase M3 + 1-phase M4. #define MAX77812_REG_RSET 0x00 #define MAX77812_REG_INT_SRC 0x01 @@ -27,7 +27,15 @@ #define MAX77812_REG_TOPSYS_INT_M 0x04 #define MAX77812_REG_TOPSYS_STAT 0x05 #define MAX77812_REG_EN_CTRL 0x06 -#define MAX77812_EN_CTRL_EN_M4 BIT(6) +#define MAX77812_EN_CTRL_ENABLE 1 +#define MAX77812_EN_CTRL_EN_M1_SHIFT 0 +#define MAX77812_EN_CTRL_EN_M1_MASK (1 << MAX77812_EN_CTRL_EN_M1_SHIFT) +#define MAX77812_EN_CTRL_EN_M2_SHIFT 2 +#define MAX77812_EN_CTRL_EN_M2_MASK (1 << MAX77812_EN_CTRL_EN_M2_SHIFT) +#define MAX77812_EN_CTRL_EN_M3_SHIFT 4 +#define MAX77812_EN_CTRL_EN_M3_MASK (1 << MAX77812_EN_CTRL_EN_M3_SHIFT) +#define MAX77812_EN_CTRL_EN_M4_SHIFT 6 +#define MAX77812_EN_CTRL_EN_M4_MASK (1 << MAX77812_EN_CTRL_EN_M4_SHIFT) #define MAX77812_REG_STUP_DLY2 0x07 #define MAX77812_REG_STUP_DLY3 0x08 #define MAX77812_REG_STUP_DLY4 0x09 @@ -46,11 +54,10 @@ #define MAX77812_REG_BUCK_INT 0x20 #define MAX77812_REG_BUCK_INT_M 0x21 #define MAX77812_REG_BUCK_STAT 0x22 -#define MAX77812_REG_M1_VOUT 0x23 +#define MAX77812_REG_M1_VOUT 0x23 // GPU. #define MAX77812_REG_M2_VOUT 0x24 -#define MAX77812_REG_M3_VOUT 0x25 -#define MAX77812_REG_M4_VOUT 0x26 -#define MAX77812_M4_VOUT_0_80V 0x6E +#define MAX77812_REG_M3_VOUT 0x25 // DRAM on PHASE211. +#define MAX77812_REG_M4_VOUT 0x26 // CPU. #define MAX77812_REG_M1_VOUT_D 0x27 #define MAX77812_REG_M2_VOUT_D 0x28 #define MAX77812_REG_M3_VOUT_D 0x29 @@ -66,6 +73,8 @@ #define MAX77812_REG_GLB_CFG1 0x33 #define MAX77812_REG_GLB_CFG2 0x34 #define MAX77812_REG_GLB_CFG3 0x35 + +/*! Protected area and settings only for MAX77812_REG_VERSION 4 */ #define MAX77812_REG_GLB_CFG4 0x36 #define MAX77812_REG_GLB_CFG5 0x37 #define MAX77812_REG_GLB_CFG6 0x38 @@ -91,10 +100,6 @@ #define MAX77812_ES2_VERSION 0x04 #define MAX77812_QS_VERSION 0x05 -#define MAX77812_VOUT_MASK 0xFF -#define MAX77812_VOUT_N_VOLTAGE 0xFF -#define MAX77812_VOUT_VMIN 250000 -#define MAX77812_VOUT_VMAX 1525000 -#define MAX77812_VOUT_STEP 5000 +#define MAX77812_BUCK_VOLT_MASK 0xFF #endif diff --git a/bdk/power/regulator_5v.c b/bdk/power/regulator_5v.c index c61db64..64fd7d7 100644 --- a/bdk/power/regulator_5v.c +++ b/bdk/power/regulator_5v.c @@ -21,8 +21,9 @@ #include static u8 reg_5v_dev = 0; +static bool batt_src = false; -void regulator_enable_5v(u8 dev) +void regulator_5v_enable(u8 dev) { // The power supply selection from battery or USB is automatic. if (!reg_5v_dev) @@ -32,6 +33,7 @@ void regulator_enable_5v(u8 dev) 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); + batt_src = true; // Fan and Rail power from USB 5V VDD. PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1; @@ -47,7 +49,7 @@ void regulator_enable_5v(u8 dev) reg_5v_dev |= dev; } -void regulator_disable_5v(u8 dev) +void regulator_5v_disable(u8 dev) { reg_5v_dev &= ~dev; @@ -58,6 +60,7 @@ void regulator_disable_5v(u8 dev) 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; + batt_src = false; // Rail power from USB 5V VDD. gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); @@ -70,7 +73,21 @@ void regulator_disable_5v(u8 dev) } } -bool regulator_get_5v_dev_enabled(u8 dev) +bool regulator_5v_get_dev_enabled(u8 dev) { return (reg_5v_dev & dev); } + +void regulator_5v_batt_src_enable(bool enable) +{ + if (enable && !batt_src) + { + gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH); + batt_src = true; + } + else if (!enable && batt_src) + { + gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW); + batt_src = false; + } +} diff --git a/bdk/power/regulator_5v.h b/bdk/power/regulator_5v.h index 6bb837a..b7d7490 100644 --- a/bdk/power/regulator_5v.h +++ b/bdk/power/regulator_5v.h @@ -27,8 +27,9 @@ enum REGULATOR_5V_ALL = 0xFF }; -void regulator_enable_5v(u8 dev); -void regulator_disable_5v(u8 dev); -bool regulator_get_5v_dev_enabled(u8 dev); +void regulator_5v_enable(u8 dev); +void regulator_5v_disable(u8 dev); +bool regulator_5v_get_dev_enabled(u8 dev); +void regulator_5v_batt_src_enable(bool enable); #endif \ No newline at end of file diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 2f76985..92767b9 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018 Atmosphère-NX - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -35,8 +35,8 @@ typedef struct _se_ll_t vu32 size; } se_ll_t; -static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT]; -static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT]; +static u32 _se_rsa_mod_sizes[SE_RSA_KEYSLOT_COUNT]; +static u32 _se_rsa_exp_sizes[SE_RSA_KEYSLOT_COUNT]; static void _gf256_mul_x(void *block) { @@ -79,17 +79,17 @@ static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) static void _se_ll_set(se_ll_t *dst, se_ll_t *src) { - SE(SE_IN_LL_ADDR_REG_OFFSET) = (u32)src; - SE(SE_OUT_LL_ADDR_REG_OFFSET) = (u32)dst; + SE(SE_IN_LL_ADDR_REG) = (u32)src; + SE(SE_OUT_LL_ADDR_REG) = (u32)dst; } static int _se_wait() { - while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET))) + while (!(SE(SE_INT_STATUS_REG) & SE_INT_OP_DONE)) ; - if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) || - SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN || - SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) + if (SE(SE_INT_STATUS_REG) & SE_INT_ERR_STAT || + (SE(SE_STATUS_REG) & SE_STATUS_STATE_MASK) != SE_STATUS_STATE_IDLE || + SE(SE_ERR_STATUS_REG) != 0) return 0; return 1; } @@ -114,12 +114,12 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src _se_ll_set(ll_dst, ll_src); - SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); - SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); + SE(SE_ERR_STATUS_REG) = SE(SE_ERR_STATUS_REG); + SE(SE_INT_STATUS_REG) = SE(SE_INT_STATUS_REG); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + SE(SE_OPERATION_REG) = op; if (is_oneshot) { @@ -168,13 +168,13 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr if (!src || !dst) return 0; - u8 *block = (u8 *)malloc(0x10); - memset(block, 0, 0x10); + u8 *block = (u8 *)malloc(SE_AES_BLOCK_SIZE); + memset(block, 0, SE_AES_BLOCK_SIZE); - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; memcpy(block, src, src_size); - int res = _se_execute_oneshot(op, block, 0x10, block, 0x10); + int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE); memcpy(dst, block, dst_size); free(block); @@ -183,21 +183,21 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr static void _se_aes_ctr_set(void *ctr) { - u32 data[TEGRA_SE_AES_BLOCK_SIZE / 4]; - memcpy(data, ctr, TEGRA_SE_AES_BLOCK_SIZE); + u32 data[SE_AES_IV_SIZE / 4]; + memcpy(data, ctr, SE_AES_IV_SIZE); - for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) - SE(SE_CRYPTO_CTR_REG_OFFSET + (4 * i)) = data[i]; + for (u32 i = 0; i < SE_CRYPTO_LINEAR_CTR_REG_COUNT; i++) + SE(SE_CRYPTO_LINEAR_CTR_REG + (4 * i)) = data[i]; } void se_rsa_acc_ctrl(u32 rs, u32 flags) { - if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = - ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | - ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); - if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~BIT(rs); + if (flags & SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_REG + 4 * rs) = + (((flags >> 4) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |(flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG)) ^ + SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG; + if (flags & SE_RSA_KEY_LOCK_FLAG) + SE(SE_RSA_SECURITY_PERKEY_REG) &= ~BIT(rs); } // se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot @@ -206,15 +206,15 @@ void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 u32 *data = (u32 *)mod; for (u32 i = 0; i < mod_size / 4; i++) { - SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i; - SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]); + SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i; + SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[mod_size / 4 - i - 1]); } data = (u32 *)exp; for (u32 i = 0; i < exp_size / 4; i++) { - SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i; - SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]); + SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i; + SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[exp_size / 4 - i - 1]); } _se_rsa_mod_sizes[ks] = mod_size; @@ -224,15 +224,15 @@ void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 // se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot void se_rsa_key_clear(u32 ks) { - for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++) + for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++) { - SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i; - SE(SE_RSA_KEYTABLE_DATA) = 0; + SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i; + SE(SE_RSA_KEYTABLE_DATA_REG) = 0; } - for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++) + for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++) { - SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i; - SE(SE_RSA_KEYTABLE_DATA) = 0; + SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i; + SE(SE_RSA_KEYTABLE_DATA_REG) = 0; } } @@ -240,22 +240,22 @@ void se_rsa_key_clear(u32 ks) int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) { int res; - u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE]; + u8 stack_buf[SE_RSA2048_DIGEST_SIZE]; for (u32 i = 0; i < src_size; i++) stack_buf[i] = *((u8 *)src + src_size - i - 1); - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG); SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks); - SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1; - SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2; + SE(SE_RSA_KEY_SIZE_REG) = (_se_rsa_mod_sizes[ks] >> 6) - 1; + SE(SE_RSA_EXP_SIZE_REG) = _se_rsa_exp_sizes[ks] >> 2; - res = _se_execute_oneshot(OP_START, NULL, 0, stack_buf, src_size); + res = _se_execute_oneshot(SE_OP_START, NULL, 0, stack_buf, src_size); // Copy output hash. u32 *dst32 = (u32 *)dst; for (u32 i = 0; i < dst_size / 4; i++) - dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2))); + dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT_REG + (i << 2))); return res; } @@ -263,54 +263,54 @@ int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_siz void se_key_acc_ctrl(u32 ks, u32 flags) { if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; - if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~BIT(ks); + SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks) = ~flags; + if (flags & SE_KEY_LOCK_FLAG) + SE(SE_CRYPTO_SECURITY_PERKEY_REG) &= ~BIT(ks); } u32 se_key_acc_ctrl_get(u32 ks) { - return SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks); + return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks); } void se_aes_key_set(u32 ks, const void *key, u32 size) { - u32 data[TEGRA_SE_AES_MAX_KEY_SIZE / 4]; + u32 data[SE_AES_MAX_KEY_SIZE / 4]; memcpy(data, key, size); for (u32 i = 0; i < (size / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; - SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i]; } } void se_aes_key_partial_set(u32 ks, u32 index, u32 data) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | index; - SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data; + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | index; + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data; } void se_aes_iv_set(u32 ks, const void *iv) { - u32 data[TEGRA_SE_AES_BLOCK_SIZE / 4]; - memcpy(data, iv, TEGRA_SE_AES_BLOCK_SIZE); + u32 data[SE_AES_IV_SIZE / 4]; + memcpy(data, iv, SE_AES_IV_SIZE); - for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) + for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(QUAD_ORG_IV) | i; - SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i); + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i]; } } void se_aes_key_get(u32 ks, void *key, u32 size) { - u32 data[TEGRA_SE_AES_MAX_KEY_SIZE / 4]; + u32 data[SE_AES_MAX_KEY_SIZE / 4]; for (u32 i = 0; i < (size / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; - data[i] = SE(SE_KEYTABLE_DATA0_REG_OFFSET); + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + data[i] = SE(SE_CRYPTO_KEYTABLE_DATA_REG); } memcpy(key, data, size); @@ -318,77 +318,77 @@ void se_aes_key_get(u32 ks, void *key, u32 size) void se_aes_key_clear(u32 ks) { - for (u32 i = 0; i < (TEGRA_SE_AES_MAX_KEY_SIZE / 4); i++) + for (u32 i = 0; i < (SE_AES_MAX_KEY_SIZE / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; - SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0; } } void se_aes_iv_clear(u32 ks) { - for (u32 i = 0; i < (TEGRA_SE_AES_BLOCK_SIZE / 4); i++) + for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++) { - SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(QUAD_ORG_IV) | i; - SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i); + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0; } } int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; + SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | SE_KEYTABLE_DST_WORD_QUAD(KEYS_0_3); - return _se_execute_oneshot(OP_START, NULL, 0, input, 0x10); + return _se_execute_oneshot(SE_OP_START, NULL, 0, input, SE_KEY_128_SIZE); } int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) { if (enc) { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); } else { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); } - SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size); } int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) { if (enc) { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP); } else { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) | + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM); } - SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size); } int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) { - return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); + return se_aes_crypt_ecb(ks, enc, dst, SE_AES_BLOCK_SIZE, src, SE_AES_BLOCK_SIZE); } int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) { - SE(SE_SPARE_0_REG_OFFSET) = 1; - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); + SE(SE_SPARE_REG) = SE_ECO(SE_ERRATA_FIX_ENABLE); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_CNTN(1); _se_aes_ctr_set(ctr); u32 src_size_aligned = src_size & 0xFFFFFFF0; @@ -396,13 +396,13 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s if (src_size_aligned) { - SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; - if (!_se_execute_oneshot(OP_START, dst, dst_size, src, src_size_aligned)) + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + if (!_se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size_aligned)) return 0; } if (src_size - src_size_aligned && src_size_aligned < dst_size) - return _se_execute_one_block(OP_START, dst + src_size_aligned, + return _se_execute_one_block(SE_OP_START, dst + src_size_aligned, MIN(src_size_delta, dst_size - src_size_aligned), src + src_size_aligned, src_size_delta); @@ -419,15 +419,15 @@ int se_initialize_rng() u8 *output_buf = (u8 *)malloc(0x10); - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); - SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001; - SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | - SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(SRC_ENTROPY); + SE(SE_RNG_RESEED_INTERVAL_REG) = 70001; + SE(SE_RNG_SRC_CONFIG_REG) = SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE) | + SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(RO_ENTR_LOCK_ENABLE); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0; - int res =_se_execute_oneshot(OP_START, output_buf, 0x10, NULL, 0); + int res =_se_execute_oneshot(SE_OP_START, output_buf, 0x10, NULL, 0); free(output_buf); if (res) @@ -437,35 +437,35 @@ int se_initialize_rng() int se_generate_random(void *dst, u32 size) { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_NORMAL) | SE_RNG_CONFIG_SRC(SRC_ENTROPY); u32 num_blocks = size >> 4; u32 aligned_size = num_blocks << 4; if (num_blocks) { - SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 1; - if (!_se_execute_oneshot(OP_START, dst, aligned_size, NULL, 0)) + SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 1; + if (!_se_execute_oneshot(SE_OP_START, dst, aligned_size, NULL, 0)) return 0; } if (size > aligned_size) - return _se_execute_one_block(OP_START, dst + aligned_size, size - aligned_size, NULL, 0); + return _se_execute_one_block(SE_OP_START, dst + aligned_size, size - aligned_size, NULL, 0); return 1; } int se_generate_random_key(u32 ks_dst, u32 ks_src) { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_NORMAL) | SE_RNG_CONFIG_SRC(SRC_ENTROPY); - SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); - if (!_se_execute_oneshot(OP_START, NULL, 0, NULL, 0)) + SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst); + if (!_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0)) return 0; - SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1; - if (!_se_execute_oneshot(OP_START, NULL, 0, NULL, 0)) + SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1; + if (!_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0)) return 0; return 1; @@ -544,8 +544,8 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) if (src_size & 0xF) _gf256_mul_x(key); - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_MEMORY) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); se_aes_iv_clear(ks); @@ -553,10 +553,10 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) u32 num_blocks = (src_size + 0xf) >> 4; if (num_blocks > 1) { - SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2; - if (!_se_execute_oneshot(OP_START, NULL, 0, src, src_size)) + SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 2; + if (!_se_execute_oneshot(SE_OP_START, NULL, 0, src, src_size)) goto out; - SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED); + SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED); } if (src_size & 0xf) @@ -572,12 +572,12 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) for (u32 i = 0; i < 0x10; i++) last_block[i] ^= key[i]; - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - res = _se_execute_oneshot(OP_START, NULL, 0, last_block, 0x10); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0; + res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, 0x10); u32 *dst32 = (u32 *)dst; for (u32 i = 0; i < (dst_size >> 2); i++) - dst32[i] = SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)); + dst32[i] = SE(SE_HASH_RESULT_REG + (i << 2)); out:; free(key); @@ -588,62 +588,62 @@ out:; int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) { int res; - u32 hash32[TEGRA_SE_SHA_256_SIZE / 4]; + u32 hash32[SE_SHA_256_SIZE / 4]; //! TODO: src_size must be 512 bit aligned if continuing and not last block for SHA256. if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. return 0; // Setup config for SHA256. - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = sha_cfg; - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); + SE(SE_SHA_CONFIG_REG) = sha_cfg; + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; // Set total size to current buffer size if empty. if (!total_size) total_size = src_size; // Set total size: BITS(src_size), up to 2 EB. - SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(total_size << 3); - SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = (u32)(total_size >> 29); - SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_0_REG) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LENGTH_2_REG) = 0; + SE(SE_SHA_MSG_LENGTH_3_REG) = 0; // Set size left to hash. - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(total_size << 3); - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = (u32)(total_size >> 29); - SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_0_REG) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LEFT_2_REG) = 0; + SE(SE_SHA_MSG_LEFT_3_REG) = 0; // If we hash in chunks, copy over the intermediate. if (sha_cfg == SHA_CONTINUE && msg_left) { // Restore message left to process. - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = msg_left[0]; - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = msg_left[1]; + SE(SE_SHA_MSG_LEFT_0_REG) = msg_left[0]; + SE(SE_SHA_MSG_LEFT_1_REG) = msg_left[1]; // Restore hash reg. - memcpy(hash32, hash, TEGRA_SE_SHA_256_SIZE); - for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) - SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)) = byte_swap_32(hash32[i]); + memcpy(hash32, hash, SE_SHA_256_SIZE); + for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) + SE(SE_HASH_RESULT_REG + (i * 4)) = byte_swap_32(hash32[i]); } // Trigger the operation. - res = _se_execute(OP_START, NULL, 0, src, src_size, is_oneshot); + res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot); if (is_oneshot) { // Backup message left. if (msg_left) { - msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); - msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG); } // Copy output hash. - for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) - hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); - memcpy(hash, hash32, TEGRA_SE_SHA_256_SIZE); + for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4))); + memcpy(hash, hash32, SE_SHA_256_SIZE); } return res; @@ -656,20 +656,20 @@ int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size) int se_calc_sha256_finalize(void *hash, u32 *msg_left) { - u32 hash32[TEGRA_SE_SHA_256_SIZE / 4]; + u32 hash32[SE_SHA_256_SIZE / 4]; int res = _se_execute_finalize(); // Backup message left. if (msg_left) { - msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); - msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG); } // Copy output hash. - for (u32 i = 0; i < (TEGRA_SE_SHA_256_SIZE / 4); i++) - hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); - memcpy(hash, hash32, TEGRA_SE_SHA_256_SIZE); + for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i << 2))); + memcpy(hash, hash32, SE_SHA_256_SIZE); return res; } @@ -793,43 +793,43 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40); // Set Secure Random Key. - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); - SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_FORCE_RESEED); SE(SE_CRYPTO_LAST_BLOCK) = 0; - _se_execute_oneshot(OP_START, NULL, 0, NULL, 0); + _se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0); // Save AES keys. - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++) + for (u32 i = 0; i < SE_AES_KEYSLOT_COUNT; i++) { - SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | - (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3); + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) | + SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_0_3); SE(SE_CRYPTO_LAST_BLOCK) = 0; - _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); - memcpy(keys + i * keysize, aligned_buf, 0x10); + _se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0); + memcpy(keys + i * keysize, aligned_buf, SE_AES_BLOCK_SIZE); - if (keysize > 0x10) + if (keysize > SE_KEY_128_SIZE) { - SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | - (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7); + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) | + SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_4_7); SE(SE_CRYPTO_LAST_BLOCK) = 0; - _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); - memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10); + _se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0); + memcpy(keys + i * keysize + SE_AES_BLOCK_SIZE, aligned_buf, SE_AES_BLOCK_SIZE); } } // Save SRK to PMC secure scratches. - SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK); - SE(SE_CRYPTO_LAST_BLOCK) = 0; - _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(SRK); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0); // End context save. - SE(SE_CONFIG_REG_OFFSET) = 0; - _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + SE(SE_CONFIG_REG) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0); // Get SRK. u32 srk[4]; @@ -840,7 +840,7 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) // Decrypt context. se_aes_key_clear(3); - se_aes_key_set(3, srk, 0x10); - se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize); + se_aes_key_set(3, srk, SE_KEY_128_SIZE); + se_aes_crypt_cbc(3, 0, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize); se_aes_key_clear(3); } diff --git a/bdk/sec/se.h b/bdk/sec/se.h index 400d865..a52fd53 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -1,5 +1,7 @@ /* * Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2021 CTCaer +* Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -25,6 +27,7 @@ void se_rsa_key_clear(u32 ks); int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); void se_key_acc_ctrl(u32 ks, u32 flags); u32 se_key_acc_ctrl_get(u32 ks); +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_iv_set(u32 ks, const void *iv); void se_aes_key_partial_set(u32 ks, u32 index, u32 data); @@ -35,10 +38,10 @@ int se_initialize_rng(); int se_generate_random(void *dst, u32 size); int se_generate_random_key(u32 ks_dst, u32 ks_src); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); -int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size); int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); @@ -47,6 +50,5 @@ int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); int se_calc_sha256_finalize(void *hash, u32 *msg_left); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); -void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); #endif diff --git a/bdk/sec/se_t210.h b/bdk/sec/se_t210.h index 6fbf1b0..0233e1d 100644 --- a/bdk/sec/se_t210.h +++ b/bdk/sec/se_t210.h @@ -1,400 +1,323 @@ /* -* Driver for Tegra Security Engine -* -* Copyright (c) 2011-2013, NVIDIA Corporation. All Rights Reserved. -* -* 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 -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2021 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 . + */ -#ifndef _CRYPTO_TEGRA_SE_H -#define _CRYPTO_TEGRA_SE_H +#ifndef _SE_T210_H +#define _SE_T210_H #include -#define TEGRA_SE_CRA_PRIORITY 300 -#define TEGRA_SE_COMPOSITE_PRIORITY 400 -#define TEGRA_SE_CRYPTO_QUEUE_LENGTH 50 -#define SE_MAX_SRC_SG_COUNT 50 -#define SE_MAX_DST_SG_COUNT 50 +#define SE_CRYPTO_QUEUE_LENGTH 50 +#define SE_MAX_SRC_SG_COUNT 50 +#define SE_MAX_DST_SG_COUNT 50 -#define TEGRA_SE_KEYSLOT_COUNT 16 -#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF +#define SE_AES_KEYSLOT_COUNT 16 +#define SE_RSA_KEYSLOT_COUNT 2 +#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF + +#define SE_AES_BLOCK_SIZE 16 +#define SE_AES_IV_SIZE 16 +#define SE_AES_MIN_KEY_SIZE 16 +#define SE_AES_MAX_KEY_SIZE 32 +#define SE_KEY_128_SIZE 16 +#define SE_KEY_192_SIZE 24 +#define SE_KEY_256_SIZE 32 +#define SE_SHA_192_SIZE 24 +#define SE_SHA_256_SIZE 32 +#define SE_SHA_384_SIZE 48 +#define SE_SHA_512_SIZE 64 +#define SE_RNG_IV_SIZE 16 +#define SE_RNG_DT_SIZE 16 +#define SE_RNG_KEY_SIZE 16 +#define SE_RNG_SEED_SIZE (SE_RNG_IV_SIZE + SE_RNG_KEY_SIZE + SE_RNG_DT_SIZE) + +#define SE_AES_CMAC_DIGEST_SIZE 16 +#define SE_RSA512_DIGEST_SIZE 64 +#define SE_RSA1024_DIGEST_SIZE 128 +#define SE_RSA1536_DIGEST_SIZE 192 +#define SE_RSA2048_DIGEST_SIZE 256 /* SE register definitions */ -#define SE_SECURITY_0 0x000 -#define SE_KEY_SCHED_READ_SHIFT 3 +#define SE_SE_SECURITY_REG 0x000 +#define SE_HARD_SETTING BIT(0) +#define SE_ENG_DIS BIT(1) +#define SE_PERKEY_SETTING BIT(2) +#define SE_SOFT_SETTING BIT(16) -#define SE_TZRAM_SECURITY_0 0x004 +#define SE_TZRAM_SECURITY_REG 0x004 +#define SE_TZRAM_HARD_SETTING BIT(0) +#define SE_TZRAM_ENG_DIS BIT(1) -#define SE_CONFIG_REG_OFFSET 0x014 -#define SE_CONFIG_ENC_ALG_SHIFT 12 -#define SE_CONFIG_DEC_ALG_SHIFT 8 -#define ALG_AES_ENC 1 -#define ALG_RNG 2 -#define ALG_SHA 3 -#define ALG_RSA 4 -#define ALG_NOP 0 -#define ALG_AES_DEC 1 -#define SE_CONFIG_ENC_ALG(x) ((x) << SE_CONFIG_ENC_ALG_SHIFT) -#define SE_CONFIG_DEC_ALG(x) ((x) << SE_CONFIG_DEC_ALG_SHIFT) -#define SE_CONFIG_DST_SHIFT 2 -#define DST_MEMORY 0 -#define DST_HASHREG 1 -#define DST_KEYTAB 2 -#define DST_SRK 3 -#define DST_RSAREG 4 -#define SE_CONFIG_DST(x) ((x) << SE_CONFIG_DST_SHIFT) -#define SE_CONFIG_ENC_MODE_SHIFT 24 -#define SE_CONFIG_DEC_MODE_SHIFT 16 -#define MODE_KEY128 0 -#define MODE_KEY192 1 -#define MODE_KEY256 2 -#define MODE_SHA1 0 -#define MODE_SHA224 4 -#define MODE_SHA256 5 -#define MODE_SHA384 6 -#define MODE_SHA512 7 -#define SE_CONFIG_ENC_MODE(x) ((x) << SE_CONFIG_ENC_MODE_SHIFT) -#define SE_CONFIG_DEC_MODE(x) ((x) << SE_CONFIG_DEC_MODE_SHIFT) +#define SE_OPERATION_REG 0x008 +#define SE_OP_ABORT 0 +#define SE_OP_START 1 +#define SE_OP_RESTART_OUT 2 +#define SE_OP_CTX_SAVE 3 +#define SE_OP_RESTART_IN 4 -#define SE_RNG_CONFIG_REG_OFFSET 0x340 -#define RNG_MODE_SHIFT 0 -#define RNG_MODE_NORMAL 0 -#define RNG_MODE_FORCE_INSTANTION 1 -#define RNG_MODE_FORCE_RESEED 2 -#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_INT_ENABLE_REG 0x00C +#define SE_INT_STATUS_REG 0x010 +#define SE_INT_IN_LL_BUF_RD BIT(0) +#define SE_INT_IN_DONE BIT(1) +#define SE_INT_OUT_LL_BUF_WR BIT(2) +#define SE_INT_OUT_DONE BIT(3) +#define SE_INT_OP_DONE BIT(4) +#define SE_INT_RESEED_NEEDED BIT(5) +#define SE_INT_ERR_STAT BIT(16) -#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344 -#define RNG_SRC_RO_ENT_SHIFT 1 -#define RNG_SRC_RO_ENT_ENABLE 1 -#define RNG_SRC_RO_ENT_DISABLE 0 -#define SE_RNG_SRC_CONFIG_ENT_SRC(x) ((x) << RNG_SRC_RO_ENT_SHIFT) -#define RNG_SRC_RO_ENT_LOCK_SHIFT 0 -#define RNG_SRC_RO_ENT_LOCK_ENABLE 1 -#define RNG_SRC_RO_ENT_LOCK_DISABLE 0 -#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) ((x) << RNG_SRC_RO_ENT_LOCK_SHIFT) +#define SE_CONFIG_REG 0x014 +#define DST_MEMORY 0 +#define DST_HASHREG 1 +#define DST_KEYTABLE 2 +#define DST_SRK 3 +#define DST_RSAREG 4 +#define SE_CONFIG_DST(x) ((x) << 2) +#define ALG_NOP 0 +#define ALG_AES_DEC 1 +#define SE_CONFIG_DEC_ALG(x) ((x) << 8) +#define ALG_NOP 0 +#define ALG_AES_ENC 1 +#define ALG_RNG 2 +#define ALG_SHA 3 +#define ALG_RSA 4 +#define SE_CONFIG_ENC_ALG(x) ((x) << 12) +#define MODE_KEY128 0 +#define MODE_KEY192 1 +#define MODE_KEY256 2 +#define MODE_SHA1 0 +#define MODE_SHA224 4 +#define MODE_SHA256 5 +#define MODE_SHA384 6 +#define MODE_SHA512 7 +#define SE_CONFIG_DEC_MODE(x) ((x) << 16) +#define SE_CONFIG_ENC_MODE(x) ((x) << 24) -#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 +#define SE_IN_LL_ADDR_REG 0x018 +#define SE_IN_CUR_BYTE_ADDR_REG 0x01C +#define SE_IN_CUR_LL_ID_REG 0x020 +#define SE_OUT_LL_ADDR_REG 0x024 +#define SE_OUT_CUR_BYTE_ADDR_REG 0x028 +#define SE_OUT_CUR_LL_ID_REG 0x02C -#define SE_KEYTABLE_REG_OFFSET 0x31c -#define SE_KEYTABLE_SLOT_SHIFT 4 -#define SE_KEYTABLE_SLOT(x) ((x) << SE_KEYTABLE_SLOT_SHIFT) -#define SE_KEYTABLE_QUAD_SHIFT 2 -#define QUAD_KEYS_128 0 -#define QUAD_KEYS_192 1 -#define QUAD_KEYS_256 1 -#define QUAD_ORG_IV 2 -#define QUAD_UPDTD_IV 3 -#define SE_KEYTABLE_QUAD(x) ((x) << SE_KEYTABLE_QUAD_SHIFT) -#define SE_KEYTABLE_OP_TYPE_SHIFT 9 -#define OP_READ 0 -#define OP_WRITE 1 -#define SE_KEYTABLE_OP_TYPE(x) ((x) << SE_KEYTABLE_OP_TYPE_SHIFT) -#define SE_KEYTABLE_TABLE_SEL_SHIFT 8 -#define TABLE_KEYIV 0 -#define TABLE_SCHEDULE 1 -#define SE_KEYTABLE_TABLE_SEL(x) ((x) << SE_KEYTABLE_TABLE_SEL_SHIFT) -#define SE_KEYTABLE_PKT_SHIFT 0 -#define SE_KEYTABLE_PKT(x) ((x) << SE_KEYTABLE_PKT_SHIFT) +#define SE_HASH_RESULT_REG 0x030 +#define SE_HASH_RESULT_REG_COUNT 16 -#define SE_OP_DONE_SHIFT 4 -#define OP_DONE 1 -#define SE_OP_DONE(x, y) ((x) && ((y) << SE_OP_DONE_SHIFT)) +#define SE_CONTEXT_SAVE_CONFIG_REG 0x070 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_CONTEXT_AES_WORD_QUAD(x) ((x) << 0) +#define SE_CONTEXT_AES_KEY_INDEX(x) ((x) << 8) +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define KEYS_8_11 2 +#define KEYS_12_15 3 +#define SE_CONTEXT_RSA_WORD_QUAD(x) ((x) << 12) +#define SLOT0_EXPONENT 0 +#define SLOT0_MODULUS 1 +#define SLOT1_EXPONENT 2 +#define SLOT1_MODULUS 3 +#define SE_CONTEXT_RSA_KEY_INDEX(x) ((x) << 16) +#define STICKY_0_3 0 +#define STICKY_4_7 1 +#define SE_CONTEXT_STICKY_WORD_QUAD(x) ((x) << 24) +#define STICKY_BITS 0 +#define RSA_KEYTABLE 1 +#define AES_KEYTABLE 2 +#define MEM 4 +#define SRK 6 +#define SE_CONTEXT_SRC(x) ((x) << 29) -#define SE_CRYPTO_LAST_BLOCK 0x080 +#define SE_CTX_SAVE_AUTO_T210B01_REG 0x074 +#define SE_CTX_SAVE_AUTO_ENABLE BIT(0) +#define SE_CTX_SAVE_AUTO_LOCK BIT(8) +#define SE_CTX_SAVE_AUTO_CURR_CNT_MASK (0x3FF << 16) -#define SE_CRYPTO_REG_OFFSET 0x304 -#define SE_CRYPTO_HASH_SHIFT 0 -#define HASH_DISABLE 0 -#define HASH_ENABLE 1 -#define SE_CRYPTO_HASH(x) ((x) << SE_CRYPTO_HASH_SHIFT) -#define SE_CRYPTO_XOR_POS_SHIFT 1 -#define XOR_BYPASS 0 -#define XOR_TOP 2 -#define XOR_BOTTOM 3 -#define SE_CRYPTO_XOR_POS(x) ((x) << SE_CRYPTO_XOR_POS_SHIFT) -#define SE_CRYPTO_INPUT_SEL_SHIFT 3 -#define INPUT_AHB 0 -#define INPUT_RANDOM 1 -#define INPUT_AESOUT 2 -#define INPUT_LNR_CTR 3 -#define SE_CRYPTO_INPUT_SEL(x) ((x) << SE_CRYPTO_INPUT_SEL_SHIFT) -#define SE_CRYPTO_VCTRAM_SEL_SHIFT 5 -#define VCTRAM_AHB 0 -#define VCTRAM_AESOUT 2 -#define VCTRAM_PREVAHB 3 -#define SE_CRYPTO_VCTRAM_SEL(x) ((x) << SE_CRYPTO_VCTRAM_SEL_SHIFT) -#define SE_CRYPTO_IV_SEL_SHIFT 7 -#define IV_ORIGINAL 0 -#define IV_UPDATED 1 -#define SE_CRYPTO_IV_SEL(x) ((x) << SE_CRYPTO_IV_SEL_SHIFT) -#define SE_CRYPTO_CORE_SEL_SHIFT 8 -#define CORE_DECRYPT 0 -#define CORE_ENCRYPT 1 -#define SE_CRYPTO_CORE_SEL(x) ((x) << SE_CRYPTO_CORE_SEL_SHIFT) -#define SE_CRYPTO_CTR_VAL_SHIFT 11 -#define SE_CRYPTO_CTR_VAL(x) ((x) << SE_CRYPTO_CTR_VAL_SHIFT) -#define SE_CRYPTO_KEY_INDEX_SHIFT 24 -#define SE_CRYPTO_KEY_INDEX(x) ((x) << SE_CRYPTO_KEY_INDEX_SHIFT) -#define SE_CRYPTO_CTR_CNTN_SHIFT 11 -#define SE_CRYPTO_CTR_CNTN(x) ((x) << SE_CRYPTO_CTR_CNTN_SHIFT) +#define SE_CRYPTO_LAST_BLOCK 0x080 -#define SE_CRYPTO_CTR_REG_COUNT 4 -#define SE_CRYPTO_CTR_REG_OFFSET 0x308 - -#define SE_OPERATION_REG_OFFSET 0x008 -#define SE_OPERATION_SHIFT 0 -#define OP_ABORT 0 -#define OP_START 1 -#define OP_RESTART 2 -#define OP_CTX_SAVE 3 -#define OP_RESTART_IN 4 -#define SE_OPERATION(x) ((x) << SE_OPERATION_SHIFT) - -#define SE_CONTEXT_SAVE_CONFIG_REG_OFFSET 0x070 -#define SE_CONTEXT_SAVE_WORD_QUAD_SHIFT 0 -#define KEYS_0_3 0 -#define KEYS_4_7 1 -#define ORIG_IV 2 -#define UPD_IV 3 -#define SE_CONTEXT_SAVE_WORD_QUAD(x) ((x) << SE_CONTEXT_SAVE_WORD_QUAD_SHIFT) - -#define SE_CONTEXT_SAVE_KEY_INDEX_SHIFT 8 -#define SE_CONTEXT_SAVE_KEY_INDEX(x) ((x) << SE_CONTEXT_SAVE_KEY_INDEX_SHIFT) - -#define SE_CONTEXT_SAVE_STICKY_WORD_QUAD_SHIFT 24 -#define STICKY_0_3 0 -#define STICKY_4_7 1 -#define SE_CONTEXT_SAVE_STICKY_WORD_QUAD(x) \ - ((x) << SE_CONTEXT_SAVE_STICKY_WORD_QUAD_SHIFT) - -#define SE_CONTEXT_SAVE_SRC_SHIFT 29 -#define STICKY_BITS 0 -#define KEYTABLE 2 -#define MEM 4 -#define SRK 6 - -#define RSA_KEYTABLE 1 -#define AES_KEYTABLE 2 -#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(x) \ - ((x) << SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT) - -#define SE_CONTEXT_RSA_WORD_QUAD_SHIFT 12 -#define SE_CONTEXT_RSA_WORD_QUAD(x) \ - ((x) << SE_CONTEXT_RSA_WORD_QUAD_SHIFT) - -#define SE_CTX_SAVE_AUTO 0x074 -#define CTX_SAVE_AUTO_ENABLE BIT(0) -#define CTX_SAVE_AUTO_LOCK BIT(8) -#define CTX_SAVE_AUTO_CURR_CNT_MASK (0x3FF << 16) - -#define SE_INT_ENABLE_REG_OFFSET 0x00c -#define SE_INT_STATUS_REG_OFFSET 0x010 -#define INT_DISABLE 0 -#define INT_ENABLE 1 -#define INT_UNSET 0 -#define INT_SET 1 -#define SE_INT_OP_DONE_SHIFT 4 -#define SE_INT_OP_DONE(x) ((x) << SE_INT_OP_DONE_SHIFT) -#define SE_INT_ERROR_SHIFT 16 -#define SE_INT_ERROR(x) ((x) << SE_INT_ERROR_SHIFT) - -#define SE_STATUS_0 0x800 -#define SE_STATUS_0_STATE_WAIT_IN 3 - -#define SE_ERR_STATUS_0 0x804 -#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 - -#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 -#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 -#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \ - ((x) << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) - -#define SE_KEY_INDEX_SHIFT 8 -#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) ((x) << SE_KEY_INDEX_SHIFT) - -#define SE_IN_LL_ADDR_REG_OFFSET 0x018 -#define SE_OUT_LL_ADDR_REG_OFFSET 0x024 - -#define SE_KEYTABLE_DATA0_REG_OFFSET 0x320 -#define SE_KEYTABLE_REG_MAX_DATA 16 - -#define SE_BLOCK_COUNT_REG_OFFSET 0x318 - -#define SE_SPARE_0_REG_OFFSET 0x80c - -#define SE_SHA_CONFIG_REG_OFFSET 0x200 +#define SE_SHA_CONFIG_REG 0x200 #define SHA_CONTINUE 0 #define SHA_INIT_HASH 1 -#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 -#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 -#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C -#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 -#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 -#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 -#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C -#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 +#define SE_SHA_MSG_LENGTH_0_REG 0x204 +#define SE_SHA_MSG_LENGTH_1_REG 0x208 +#define SE_SHA_MSG_LENGTH_2_REG 0x20C +#define SE_SHA_MSG_LENGTH_3_REG 0x210 +#define SE_SHA_MSG_LEFT_0_REG 0x214 +#define SE_SHA_MSG_LEFT_1_REG 0x218 +#define SE_SHA_MSG_LEFT_2_REG 0x21C +#define SE_SHA_MSG_LEFT_3_REG 0x220 -#define SE_HASH_RESULT_REG_COUNT 16 -#define SE_HASH_RESULT_REG_OFFSET 0x030 -#define TEGRA_SE_KEY_256_SIZE 32 -#define TEGRA_SE_KEY_192_SIZE 24 -#define TEGRA_SE_KEY_128_SIZE 16 -#define TEGRA_SE_AES_BLOCK_SIZE 16 -#define TEGRA_SE_AES_MIN_KEY_SIZE 16 -#define TEGRA_SE_AES_MAX_KEY_SIZE 32 -#define TEGRA_SE_AES_IV_SIZE 16 -#define TEGRA_SE_SHA_512_SIZE 64 -#define TEGRA_SE_SHA_384_SIZE 48 -#define TEGRA_SE_SHA_256_SIZE 32 -#define TEGRA_SE_SHA_192_SIZE 24 -#define TEGRA_SE_RNG_IV_SIZE 16 -#define TEGRA_SE_RNG_DT_SIZE 16 -#define TEGRA_SE_RNG_KEY_SIZE 16 -#define TEGRA_SE_RNG_SEED_SIZE (TEGRA_SE_RNG_IV_SIZE + \ - TEGRA_SE_RNG_KEY_SIZE + \ - TEGRA_SE_RNG_DT_SIZE) +#define SE_CRYPTO_SECURITY_PERKEY_REG 0x280 +#define SE_KEY_LOCK_FLAG 0x80 +#define SE_CRYPTO_KEYTABLE_ACCESS_REG 0x284 +#define SE_CRYPTO_KEYTABLE_ACCESS_REG_COUNT 16 +#define SE_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG BIT(2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG BIT(3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG BIT(4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG BIT(5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG BIT(6) +#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F -#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16 -#define TEGRA_SE_RSA512_DIGEST_SIZE 64 -#define TEGRA_SE_RSA1024_DIGEST_SIZE 128 -#define TEGRA_SE_RSA1536_DIGEST_SIZE 192 -#define TEGRA_SE_RSA2048_DIGEST_SIZE 256 +#define SE_CRYPTO_CONFIG_REG 0x304 +#define HASH_DISABLE 0 +#define HASH_ENABLE 1 +#define SE_CRYPTO_HASH(x) ((x) << 0) +#define XOR_BYPASS 0 +#define XOR_TOP 2 +#define XOR_BOTTOM 3 +#define SE_CRYPTO_XOR_POS(x) ((x) << 1) +#define INPUT_MEMORY 0 +#define INPUT_RANDOM 1 +#define INPUT_AESOUT 2 +#define INPUT_LNR_CTR 3 +#define SE_CRYPTO_INPUT_SEL(x) ((x) << 3) +#define VCTRAM_MEM 0 +#define VCTRAM_AESOUT 2 +#define VCTRAM_PREVMEM 3 +#define SE_CRYPTO_VCTRAM_SEL(x) ((x) << 5) +#define IV_ORIGINAL 0 +#define IV_UPDATED 1 +#define SE_CRYPTO_IV_SEL(x) ((x) << 7) +#define CORE_DECRYPT 0 +#define CORE_ENCRYPT 1 +#define SE_CRYPTO_CORE_SEL(x) ((x) << 8) +#define SE_CRYPTO_KEYSCH_BYPASS BIT(10) +#define SE_CRYPTO_CTR_CNTN(x) ((x) << 11) +#define SE_CRYPTO_KEY_INDEX(x) ((x) << 24) +#define MEMIF_AHB 0 +#define MEMIF_MCCIF 1 +#define SE_CRYPTO_MEMIF(x) ((x) << 31) -#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280 -#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 +#define SE_CRYPTO_LINEAR_CTR_REG 0x308 +#define SE_CRYPTO_LINEAR_CTR_REG_COUNT 4 -#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 -#define SE_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) -#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) -#define SE_KEY_TBL_DIS_OIVREAD_FLAG BIT(2) -#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG BIT(3) -#define SE_KEY_TBL_DIS_UIVREAD_FLAG BIT(4) -#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG BIT(5) -#define SE_KEY_TBL_DIS_KEYUSE_FLAG BIT(6) -#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F +#define SE_CRYPTO_BLOCK_COUNT_REG 0x318 -#define SE_KEY_READ_DISABLE_SHIFT 0 -#define SE_KEY_UPDATE_DISABLE_SHIFT 1 +#define SE_CRYPTO_KEYTABLE_ADDR_REG 0x31C +#define SE_KEYTABLE_PKT(x) ((x) << 0) +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_KEYTABLE_QUAD(x) ((x) << 2) +#define SE_KEYTABLE_SLOT(x) ((x) << 4) -#define SE_CONTEXT_BUFER_SIZE 1072 -#define SE_CONTEXT_DRBG_BUFER_SIZE 2112 +#define SE_CRYPTO_KEYTABLE_DATA_REG 0x320 -#define SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET 0 -#define SE_CONTEXT_SAVE_RANDOM_DATA_SIZE 16 -#define SE_CONTEXT_SAVE_STICKY_BITS_OFFSET \ - (SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET + SE_CONTEXT_SAVE_RANDOM_DATA_SIZE) -#define SE_CONTEXT_SAVE_STICKY_BITS_SIZE 16 +#define SE_CRYPTO_KEYTABLE_DST_REG 0x330 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_KEYTABLE_DST_WORD_QUAD(x) ((x) << 0) +#define SE_KEYTABLE_DST_KEY_INDEX(x) ((x) << 8) -#define SE_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ - SE_CONTEXT_SAVE_STICKY_BITS_SIZE) -#define SE11_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ - SE_CONTEXT_SAVE_STICKY_BITS_SIZE + \ - SE_CONTEXT_SAVE_STICKY_BITS_SIZE) +#define SE_RNG_CONFIG_REG 0x340 +#define MODE_NORMAL 0 +#define MODE_FORCE_INSTANTION 1 +#define MODE_FORCE_RESEED 2 +#define SE_RNG_CONFIG_MODE(x) ((x) << 0) +#define SRC_NONE 0 +#define SRC_ENTROPY 1 +#define SRC_LFSR 2 +#define SE_RNG_CONFIG_SRC(x) ((x) << 2) -#define SE_CONTEXT_SAVE_KEY_LENGTH 512 -#define SE_CONTEXT_ORIGINAL_IV_OFFSET (SE_CONTEXT_SAVE_KEYS_OFFSET + \ - SE_CONTEXT_SAVE_KEY_LENGTH) -#define SE11_CONTEXT_ORIGINAL_IV_OFFSET (SE11_CONTEXT_SAVE_KEYS_OFFSET + \ - SE_CONTEXT_SAVE_KEY_LENGTH) +#define SE_RNG_SRC_CONFIG_REG 0x344 +#define RO_ENTR_LOCK_DISABLE 0 +#define RO_ENTR_LOCK_ENABLE 1 +#define SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(x) ((x) << 0) +#define RO_ENTR_DISABLE 0 +#define RO_ENTR_ENABLE 1 +#define SE_RNG_SRC_CONFIG_ENTR_SRC(x) ((x) << 1) +#define RO_HW_DIS_CYA_DISABLE 0 +#define RO_HW_DIS_CYA_ENABLE 1 +#define SE_RNG_SRC_CONFIG_HW_DIS_CYA(x) ((x) << 2) +#define SE_RNG_SRC_CONFIG_ENTR_SUBSMPL(x) ((x) << 4) +#define SE_RNG_SRC_CONFIG_ENTR_DATA_FLUSH BIT(8) -#define SE_CONTEXT_ORIGINAL_IV_LENGTH 256 +#define SE_RNG_RESEED_INTERVAL_REG 0x348 -#define SE_CONTEXT_UPDATED_IV_OFFSET (SE_CONTEXT_ORIGINAL_IV_OFFSET + \ - SE_CONTEXT_ORIGINAL_IV_LENGTH) -#define SE11_CONTEXT_UPDATED_IV_OFFSET (SE11_CONTEXT_ORIGINAL_IV_OFFSET + \ - SE_CONTEXT_ORIGINAL_IV_LENGTH) +#define SE_RSA_CONFIG 0x400 +#define RSA_KEY_SLOT_ONE 0 +#define RSA_KEY_SLOT_TW0 1 +#define RSA_KEY_SLOT(x) ((x) << 24) -#define SE_CONTEXT_UPDATED_IV_LENGTH 256 +#define SE_RSA_KEY_SIZE_REG 0x404 +#define RSA_KEY_WIDTH_512 0 +#define RSA_KEY_WIDTH_1024 1 +#define RSA_KEY_WIDTH_1536 2 +#define RSA_KEY_WIDTH_2048 3 -#define SE_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET (SE_CONTEXT_UPDATED_IV_OFFSET + \ - SE_CONTEXT_UPDATED_IV_LENGTH) -#define SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET \ - (SE11_CONTEXT_UPDATED_IV_OFFSET + \ - SE_CONTEXT_UPDATED_IV_LENGTH) +#define SE_RSA_EXP_SIZE_REG 0x408 -#define SE_CONTEXT_SAVE_RSA_KEYS_OFFSET SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET +#define SE_RSA_SECURITY_PERKEY_REG 0x40C +#define SE_RSA_KEY_LOCK_FLAG 0x80 +#define SE_RSA_KEYTABLE_ACCESS_REG 0x410 +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG BIT(2) +#define SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG | SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) -#define SE_CONTEXT_SAVE_RSA_KEY_LENGTH 1024 +#define SE_RSA_KEYTABLE_ADDR_REG 0x420 +#define SE_RSA_KEYTABLE_PKT(x) ((x) << 0) +#define RSA_KEY_TYPE_EXP 0 +#define RSA_KEY_TYPE_MOD 1 +#define SE_RSA_KEYTABLE_TYPE(x) ((x) << 6) +#define RSA_KEY_NUM(x) ((x) << 7) +#define RSA_KEY_INPUT_MODE_REG 0 +#define RSA_KEY_INPUT_MODE_DMA 1 +#define SE_RSA_KEYTABLE_INPUT_MODE(x) ((x) << 8) +#define RSA_KEY_READ 0 +#define RSA_KEY_WRITE 1 +#define SE_RSA_KEY_OP(x) ((x) << 10) -#define SE_CONTEXT_SAVE_RSA_KNOWN_PATTERN_OFFSET \ - (SE_CONTEXT_SAVE_RSA_KEYS_OFFSET + SE_CONTEXT_SAVE_RSA_KEY_LENGTH) +#define SE_RSA_KEYTABLE_DATA_REG 0x424 -#define SE_CONTEXT_KNOWN_PATTERN_SIZE 16 +#define SE_RSA_OUTPUT_REG 0x428 +#define SE_RSA_OUTPUT_REG_COUNT 64 -#define TEGRA_SE_RSA_KEYSLOT_COUNT 2 +#define SE_STATUS_REG 0x800 +#define SE_STATUS_STATE_IDLE 0 +#define SE_STATUS_STATE_BUSY 1 +#define SE_STATUS_STATE_WAIT_OUT 2 +#define SE_STATUS_STATE_WAIT_IN 3 +#define SE_STATUS_STATE_MASK 3 -#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C -#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 +#define SE_ERR_STATUS_REG 0x804 +#define SE_ERR_STATUS_SE_NS_ACCESS BIT(0) +#define SE_ERR_STATUS_BUSY_REG_WR BIT(1) +#define SE_ERR_STATUS_DST BIT(2) +#define SE_ERR_STATUS_SRK_USAGE_LIMIT BIT(3) +#define SE_ERR_STATUS_TZRAM_NS_ACCESS BIT(24) +#define SE_ERR_STATUS_TZRAM_ADDRESS BIT(25) -#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 -#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) -#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) -#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG BIT(2) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT BIT(2) -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F +#define SE_MISC_REG 0x808 +#define SE_ENTROPY_NEXT_192BIT BIT(0) +#define SE_ENTROPY_VN_BYPASS BIT(1) +#define SE_CLK_OVR_ON BIT(2) -#define SE_RSA_KEYTABLE_ADDR 0x420 -#define SE_RSA_KEYTABLE_DATA 0x424 -#define SE_RSA_OUTPUT 0x428 +#define SE_SPARE_REG 0x80C +#define SE_ERRATA_FIX_DISABLE 0 +#define SE_ERRATA_FIX_ENABLE 1 +#define SE_ECO(x) ((x) << 0) -#define RSA_KEY_READ 0 -#define RSA_KEY_WRITE 1 -#define SE_RSA_KEY_OP_SHIFT 10 -#define SE_RSA_KEY_OP(x) ((x) << SE_RSA_KEY_OP_SHIFT) - -#define RSA_KEY_INPUT_MODE_REG 0 -#define RSA_KEY_INPUT_MODE_DMA 1 -#define RSA_KEY_INPUT_MODE_SHIFT 8 -#define RSA_KEY_INPUT_MODE(x) ((x) << RSA_KEY_INPUT_MODE_SHIFT) - -#define RSA_KEY_SLOT_ONE 0 -#define RSA_KEY_SLOT_TW0 1 -#define RSA_KEY_NUM_SHIFT 7 -#define RSA_KEY_NUM(x) ((x) << RSA_KEY_NUM_SHIFT) - -#define RSA_KEY_TYPE_EXP 0 -#define RSA_KEY_TYPE_MOD 1 -#define RSA_KEY_TYPE_SHIFT 6 -#define RSA_KEY_TYPE(x) ((x) << RSA_KEY_TYPE_SHIFT) - -#define SE_RSA_KEY_SIZE_REG_OFFSET 0x404 -#define SE_RSA_EXP_SIZE_REG_OFFSET 0x408 - -#define RSA_KEY_SLOT_SHIFT 24 -#define RSA_KEY_SLOT(x) ((x) << RSA_KEY_SLOT_SHIFT) -#define SE_RSA_CONFIG 0x400 - -#define RSA_KEY_PKT_WORD_ADDR_SHIFT 0 -#define RSA_KEY_PKT_WORD_ADDR(x) ((x) << RSA_KEY_PKT_WORD_ADDR_SHIFT) - -#define RSA_KEY_WORD_ADDR_SHIFT 0 -#define RSA_KEY_WORD_ADDR(x) ((x) << RSA_KEY_WORD_ADDR_SHIFT) - -#define SE_RSA_KEYTABLE_PKT_SHIFT 0 -#define SE_RSA_KEYTABLE_PKT(x) ((x) << SE_RSA_KEYTABLE_PKT_SHIFT) - -#endif /* _CRYPTO_TEGRA_SE_H */ +#endif diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index 3361144..adf5ac2 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -70,7 +70,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) u32 *pkg11_magic_off; bpmp_mmu_disable(); - bpmp_clk_rate_set(BPMP_CLK_NORMAL); + bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); // Enable clocks. clock_enable_host1x(); @@ -190,7 +190,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) if (kb == KB_TSEC_FW_EMU_COMPAT) { u32 start = get_tmr_us(); - u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; u32 key[16] = {0}; u32 kidx = 0; @@ -198,9 +198,9 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) { smmu_flush_all(); - if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]) + if (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]) { - k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; key[kidx++] = k; } @@ -269,7 +269,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; - memcpy(tsec_keys, &buf, 0x10); + memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); } out_free:; @@ -284,7 +284,7 @@ out:; clock_disable_sor_safe(); clock_disable_tsec(); bpmp_mmu_enable(); - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + bpmp_clk_rate_set(prev_fid); return res; } diff --git a/bdk/soc/bpmp.c b/bdk/soc/bpmp.c index 2e1819d..fc0e412 100644 --- a/bdk/soc/bpmp.c +++ b/bdk/soc/bpmp.c @@ -1,7 +1,7 @@ /* * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -212,43 +212,45 @@ const u8 pll_divn[] = { //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. }; -bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; +bpmp_freq_t bpmp_fid_current = 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; + bpmp_fid_current = BPMP_CLK_NORMAL; else { - bpmp_clock_set = BPMP_CLK_HIGH_BOOST; + bpmp_fid_current = 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; + bpmp_fid_current = i; break; } } } } -void bpmp_clk_rate_set(bpmp_freq_t fid) +bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid) { + bpmp_freq_t prev_fid = bpmp_fid_current; + if (fid > (BPMP_CLK_MAX - 1)) fid = BPMP_CLK_MAX - 1; - if (bpmp_clock_set == fid) - return; + if (prev_fid == fid) + return prev_fid; if (fid) { - if (bpmp_clock_set) + if (prev_fid) { - // Restore to PLLP source during PLLC4 configuration. + // Restore to PLLP source during PLLC configuration. CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. msleep(1); // Wait a bit for clock source change. } @@ -269,7 +271,10 @@ void bpmp_clk_rate_set(bpmp_freq_t fid) // Disable PLLC to save power. clock_disable_pllc(); } - bpmp_clock_set = fid; + bpmp_fid_current = fid; + + // Return old fid in case of temporary swap. + return prev_fid; } // The following functions halt BPMP to reduce power while sleeping. diff --git a/bdk/soc/bpmp.h b/bdk/soc/bpmp.h index 81f000b..0f80150 100644 --- a/bdk/soc/bpmp.h +++ b/bdk/soc/bpmp.h @@ -1,7 +1,7 @@ /* * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -53,6 +53,7 @@ typedef enum BPMP_CLK_MAX } bpmp_freq_t; +#define BPMP_CLK_LOWER_BOOST BPMP_CLK_SUPER_BOOST #define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST void bpmp_mmu_maintenance(u32 op, bool force); @@ -60,7 +61,7 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); void bpmp_mmu_enable(); void bpmp_mmu_disable(); void bpmp_clk_rate_get(); -void bpmp_clk_rate_set(bpmp_freq_t fid); +bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid); void bpmp_usleep(u32 us); void bpmp_msleep(u32 ms); void bpmp_halt(); diff --git a/bdk/soc/ccplex.c b/bdk/soc/ccplex.c index a8d782d..894cb28 100644 --- a/bdk/soc/ccplex.c +++ b/bdk/soc/ccplex.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include @@ -29,27 +28,24 @@ void _ccplex_enable_power_t210() { - u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~BIT(5)); // Disable GPIO5 pinmuxing. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); + // Configure GPIO5 and enable output in order to power CPU pmic. + max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_ENABLE); - // Enable cores power. + // Configure CPU pmic. // 1-3.x: MAX77621_NFSR_ENABLE. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_HOS_CFG); + + // Set voltage and enable cores power. + max7762x_regulator_set_voltage(REGULATOR_CPU0, 950000); + max7762x_regulator_enable(REGULATOR_CPU0, true); } void _ccplex_enable_power_t210b01() { - u8 pmic_cpu_addr = !(FUSE(FUSE_RESERVED_ODM28) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR; - u8 tmp = i2c_recv_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_EN_CTRL); - i2c_send_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_EN_CTRL, tmp | MAX77812_EN_CTRL_EN_M4); - i2c_send_byte(I2C_5, pmic_cpu_addr, MAX77812_REG_M4_VOUT, MAX77812_M4_VOUT_0_80V); + // Set voltage and enable cores power. + max7762x_regulator_set_voltage(REGULATOR_CPU1, 800000); + max7762x_regulator_enable(REGULATOR_CPU1, true); } void ccplex_boot_cpu0(u32 entry) @@ -62,24 +58,31 @@ void ccplex_boot_cpu0(u32 entry) else _ccplex_enable_power_t210b01(); - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. + // Enable PLLX and set it to 300 MHz. + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_ENABLE)) // PLLX_ENABLE. { CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. usleep(2); - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02; - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02; + + // Bypass dividers. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_BYPASS | (4 << 20) | (78 << 8) | 2; // P div: 4 (5), N div: 78, M div: 2. + // Disable bypass + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = (4 << 20) | (78 << 8) | 2; + // Set PLLX_LOCK_ENABLE. CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) = (CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) & 0xFFFBFFFF) | 0x40000; - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x40404E02; + // Enable PLLX. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_ENABLE | (4 << 20) | (78 << 8) | 2; } - while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) + // Wait for PLL to stabilize. + while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_LOCK)) ; - // Configure MSELECT source and enable clock. + // Configure MSELECT source and enable clock to 102MHz. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & ~BIT(CLK_V_MSELECT)) | BIT(CLK_V_MSELECT); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_MSELECT); // Configure initial CPU clock frequency and enable clock. - CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; + CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; // PLLX_OUT0_LJ. CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_CPUG); @@ -88,12 +91,12 @@ void ccplex_boot_cpu0(u32 entry) // CAR2PMC_CPU_ACK_WIDTH should be set to 0. CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; - // Enable CPU rail. - pmc_enable_partition(0, 1); + // Enable CPU main rail. + pmc_enable_partition(POWER_RAIL_CRAIL, ENABLE); // Enable cluster 0 non-CPU rail. - pmc_enable_partition(15, 1); - // Enable CE0 rail. - pmc_enable_partition(14, 1); + pmc_enable_partition(POWER_RAIL_C0NC, ENABLE); + // Enable CPU0 rail. + pmc_enable_partition(POWER_RAIL_CE0, ENABLE); // Request and wait for RAM repair. FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; @@ -113,7 +116,7 @@ void ccplex_boot_cpu0(u32 entry) // MC(MC_TZ_SECURITY_CTRL) = 1; // Clear MSELECT reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= ~BIT(CLK_V_MSELECT); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR) = BIT(CLK_V_MSELECT); // Clear NONCPU reset. CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; // Clear CPU0 reset. diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c index cf0007e..31bdb8f 100644 --- a/bdk/soc/clock.c +++ b/bdk/soc/clock.c @@ -21,6 +21,23 @@ #include #include +typedef struct _clock_osc_t +{ + u32 freq; + u16 min; + u16 max; +} clock_osc_t; + +static const clock_osc_t _clock_osc_cnt[] = { + { 12000, 706, 757 }, + { 13000, 766, 820 }, + { 16800, 991, 1059 }, + { 19200, 1133, 1210 }, + { 26000, 1535, 1638 }, + { 38400, 2268, 2418 }, + { 48000, 2836, 3023 } +}; + /* clock_t: reset, enable, source, index, clk_src, clk_div */ static const clock_t _clock_uart[] = { @@ -42,7 +59,7 @@ static const clock_t _clock_i2c[] = { }; static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, 0 // 408MHz. }; static clock_t _clock_tzram = { @@ -50,19 +67,19 @@ static clock_t _clock_tzram = { }; static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, 3 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, 3 // 163.2MHz. }; static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, 2 // 204MHz. }; static clock_t _clock_sor_safe = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, CLK_Y_SOR_SAFE, 0, 0 }; static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, CLK_X_SOR0, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NOT_USED, CLK_X_SOR0, 0, 0 }; static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, 2 //204MHz. }; static clock_t _clock_kfuse = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_KFUSE, 0, 0 @@ -72,11 +89,11 @@ static clock_t _clock_cl_dvfs = { CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, CLK_W_DVFS, 0, 0 }; static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, 4 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, 4 // 136MHz. }; static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_L_PWM, 6, 4 // Fref: 6.4MHz. Stock PLLP / 54: 7.55MHz. + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_L_PWM, 6, 4 // Fref: 6.4MHz. HOS: PLLP / 54 = 7.55MHz. }; static clock_t _clock_sdmmc_legacy_tm = { @@ -218,13 +235,13 @@ void clock_disable_sor1() void clock_enable_kfuse() { - u32 kfuse_clk_unmask = ~BIT(CLK_H_KFUSE); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & kfuse_clk_unmask) | BIT(CLK_H_KFUSE); - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= kfuse_clk_unmask; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & kfuse_clk_unmask) | BIT(CLK_H_KFUSE); - usleep(10); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= kfuse_clk_unmask; - usleep(20); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_KFUSE); + usleep(10); // Wait 10s to prevent glitching. + + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_KFUSE); + usleep(20); // Wait 20s fo kfuse hw to init. } void clock_disable_kfuse() @@ -721,3 +738,44 @@ void clock_sdmmc_disable(u32 id) _clock_sdmmc_is_reset(id); _clock_disable_pllc4(BIT(id)); } + +u32 clock_get_osc_freq() +{ + CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = OSC_FREQ_DET_TRIG | (2 - 1); // 2 periods of 32.76KHz window. + while (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY) + ; + u32 cnt = (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_CNT); + CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = 0; + + // Return frequency in KHz. + for (u32 i = 0; i < ARRAY_SIZE(_clock_osc_cnt); i++) + if (cnt >= _clock_osc_cnt[i].min && cnt <= _clock_osc_cnt[i].max) + return _clock_osc_cnt[i].freq; + + return 0; +} + +u32 clock_get_dev_freq(clock_pto_id_t id) +{ + u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (16 - 1); // 16 periods of 32.76KHz window. + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST; + usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN; + usleep(502); + + while (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY) + ; + + u32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT; + + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0; + + u32 freq = ((cnt << 8) | 0x3E) / 125; + + return freq; +} + diff --git a/bdk/soc/clock.h b/bdk/soc/clock.h index 2f6de41..67e9b4d 100644 --- a/bdk/soc/clock.h +++ b/bdk/soc/clock.h @@ -35,6 +35,10 @@ #define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 #define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 #define CLK_RST_CONTROLLER_OSC_CTRL 0x50 +#define CLK_RST_CONTROLLER_OSC_FREQ_DET 0x58 +#define CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS 0x5C +#define CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL 0x60 +#define CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS 0x64 #define CLK_RST_CONTROLLER_PLLC_BASE 0x80 #define CLK_RST_CONTROLLER_PLLC_OUT 0x84 #define CLK_RST_CONTROLLER_PLLC_MISC 0x88 @@ -156,11 +160,18 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 #define CLK_NO_SOURCE 0x0 +#define CLK_NOT_USED 0x0 /*! PLL control and status bits */ +#define PLLX_BASE_LOCK BIT(27) +#define PLLX_BASE_REF_DIS BIT(29) +#define PLLX_BASE_ENABLE BIT(30) +#define PLLX_BASE_BYPASS BIT(31) + #define PLLCX_BASE_LOCK BIT(27) #define PLLCX_BASE_REF_DIS BIT(29) #define PLLCX_BASE_ENABLE BIT(30) +#define PLLCX_BASE_BYPASS BIT(31) #define PLLA_OUT0_RSTN_CLR BIT(0) #define PLLA_OUT0_CLKEN BIT(1) @@ -178,6 +189,140 @@ #define UTMIPLL_LOCK BIT(31) +/*! PTO_CLK_CNT */ +#define PTO_REF_CLK_WIN_CFG_MASK 0xF +#define PTO_REF_CLK_WIN_CFG_16P 0xF +#define PTO_CNT_EN BIT(9) +#define PTO_CNT_RST BIT(10) +#define PTO_CLK_ENABLE BIT(13) +#define PTO_SRC_SEL_SHIFT 14 +#define PTO_SRC_SEL_MASK 0x1FF +#define PTO_DIV_SEL_MASK (3 << 23) +#define PTO_DIV_SEL_GATED (0 << 23) +#define PTO_DIV_SEL_DIV1 (1 << 23) +#define PTO_DIV_SEL_DIV2_RISING (2 << 23) +#define PTO_DIV_SEL_DIV2_FALLING (3 << 23) +#define PTO_DIV_SEL_CPU_EARLY (0 << 23) +#define PTO_DIV_SEL_CPU_LATE (1 << 23) + +#define PTO_CLK_CNT_BUSY BIT(31) +#define PTO_CLK_CNT 0xFFFFFF + +/*! OSC_FREQ_DET */ +#define OSC_REF_CLK_WIN_CFG_MASK 0xF +#define OSC_FREQ_DET_TRIG BIT(31) + +#define OSC_FREQ_DET_BUSY BIT(31) +#define OSC_FREQ_DET_CNT 0xFFFF + +/*! PLLs omitted as they need PTO enabled in MISC registers. Norm div is 2. */ +typedef enum _clock_pto_id_t +{ + CLK_PTO_PCLK_SYS = 0x06, + CLK_PTO_HCLK_SYS = 0x07, + + CLK_PTO_UTMIP_240 = 0x0C, + + CLK_PTO_CCLK_G = 0x12, + CLK_PTO_CCLK_G_DIV2 = 0x13, + + CLK_PTO_SPI1 = 0x17, + CLK_PTO_SPI2 = 0x18, + CLK_PTO_SPI3 = 0x19, + CLK_PTO_SPI4 = 0x1A, + CLK_PTO_MAUD = 0x1B, + CLK_PTO_SCLK = 0x1C, + + CLK_PTO_SDMMC1 = 0x20, + CLK_PTO_SDMMC2 = 0x21, + CLK_PTO_SDMMC3 = 0x22, + CLK_PTO_SDMMC4 = 0x23, + CLK_PTO_EMC = 0x24, + + CLK_PTO_MSELECT = 0x2F, + + CLK_PTO_VIC = 0x36, + + CLK_PTO_NVDEC = 0x39, + + CLK_PTO_NVENC = 0x3A, + CLK_PTO_NVJPG = 0x3B, + CLK_PTO_TSEC = 0x3C, + CLK_PTO_TSECB = 0x3D, + CLK_PTO_SE = 0x3E, + + CLK_PTO_DSIA_LP = 0x62, + + CLK_PTO_ISP = 0x64, + CLK_PTO_MC = 0x6A, + + CLK_PTO_ACTMON = 0x6B, + CLK_PTO_CSITE = 0x6C, + + CLK_PTO_HOST1X = 0x6F, + + CLK_PTO_SE_2 = 0x74, // Same as CLK_PTO_SE. + CLK_PTO_SOC_THERM = 0x75, + + CLK_PTO_TSEC_2 = 0x77, // Same as CLK_PTO_TSEC. + + CLK_PTO_ACLK = 0x7C, + CLK_PTO_QSPI = 0x7D, + + CLK_PTO_I2S1 = 0x80, + CLK_PTO_I2S2 = 0x81, + CLK_PTO_I2S3 = 0x82, + CLK_PTO_I2S4 = 0x83, + CLK_PTO_I2S5 = 0x84, + CLK_PTO_AHUB = 0x85, + CLK_PTO_APE = 0x86, + + CLK_PTO_DVFS_SOC = 0x88, + CLK_PTO_DVFS_REF = 0x89, + + CLK_PTO_SPDIF = 0x8F, + CLK_PTO_SPDIF_IN = 0x90, + CLK_PTO_UART_FST_MIPI_CAL = 0x91, + + CLK_PTO_PWM = 0x93, + CLK_PTO_I2C1 = 0x94, + CLK_PTO_I2C2 = 0x95, + CLK_PTO_I2C3 = 0x96, + CLK_PTO_I2C4 = 0x97, + CLK_PTO_I2C5 = 0x98, + CLK_PTO_I2C6 = 0x99, + CLK_PTO_I2C_SLOW = 0x9A, + CLK_PTO_UARTAPE = 0x9B, + + CLK_PTO_EXTPERIPH1 = 0x9D, + CLK_PTO_EXTPERIPH2 = 0x9E, + + CLK_PTO_ENTROPY = 0xA0, + CLK_PTO_UARTA = 0xA1, + CLK_PTO_UARTB = 0xA2, + CLK_PTO_UARTC = 0xA3, + CLK_PTO_UARTD = 0xA4, + CLK_PTO_OWR = 0xA5, + + CLK_PTO_HDA2CODEC_2X = 0xA7, + CLK_PTO_HDA = 0xA8, + + CLK_PTO_SDMMC_LEGACY_TM = 0xAB, + + CLK_PTO_SOR0 = 0xC0, + CLK_PTO_SOR1 = 0xC1, + + CLK_PTO_DISP2 = 0xC4, + CLK_PTO_DISP1 = 0xC5, + + CLK_PTO_XUSB_FALCON = 0x110, + + CLK_PTO_XUSB_FS = 0x136, + CLK_PTO_XUSB_SS_HOST_DEV = 0x137, + CLK_PTO_XUSB_CORE_HOST = 0x138, + CLK_PTO_XUSB_CORE_DEV = 0x139, +} clock_pto_id_t; + /* * CLOCK Peripherals: * L 0 - 31 @@ -216,7 +361,7 @@ enum CLK_L_DEV CLK_L_USBD = 22, CLK_L_ISP = 23, CLK_L_3D = 24, // HIDDEN. - //CLK_L_ = 25, + CLK_L_IDE = 25, // RESERVED. CLK_L_DISP2 = 26, CLK_L_DISP1 = 27, CLK_L_HOST1X = 28, @@ -244,11 +389,11 @@ enum CLK_H_DEV CLK_H_SPI3 = 14, CLK_H_I2C5 = 15, CLK_H_DSI = 16, - //CLK_H_ = 17, + CLK_H_TVO = 17, // RESERVED. CLK_H_HSI = 18, // HIDDEN. CLK_H_HDMI = 19, // HIDDEN. CLK_H_CSI = 20, - //CLK_H_ = 21, + CLK_H_TVDAC = 21, // RESERVED. CLK_H_I2C2 = 22, CLK_H_UARTC = 23, CLK_H_MIPI_CAL = 24, @@ -263,14 +408,14 @@ enum CLK_H_DEV enum CLK_U_DEV { - //CLK_U_ = 0, + CLK_U_SPEEDO = 0, // RESERVED. CLK_U_UARTD = 1, CLK_U_UARTE = 2, // HIDDEN. CLK_U_I2C3 = 3, CLK_U_SPI4 = 4, CLK_U_SDMMC3 = 5, CLK_U_PCIE = 6, - CLK_U_UNUSED = 7, // RESERVED + CLK_U_OWR = 7, // RESERVED. CLK_U_AFI = 8, CLK_U_CSITE = 9, CLK_U_PCIEXCLK = 10, // Only reset. @@ -444,9 +589,9 @@ enum CLK_Y_DEV /*! Generic clock descriptor. */ typedef struct _clock_t { - u32 reset; - u32 enable; - u32 source; + u16 reset; + u16 enable; + u16 source; u8 index; u8 clk_src; u8 clk_div; @@ -494,4 +639,7 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_disable(u32 id); +u32 clock_get_osc_freq(); +u32 clock_get_dev_freq(clock_pto_id_t id); + #endif diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index 62dba31..0a37a4b 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * 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 * under the terms and conditions of the GNU General Public License, @@ -76,6 +76,35 @@ u32 fuse_read_odm_keygen_rev() return 0; } +u32 fuse_read_dramid(bool raw_id) +{ + u32 dramid = (fuse_read_odm(4) & 0xF8) >> 3; + + if (raw_id) + return dramid; + + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + if (dramid > 6) + dramid = 0; + } + else + { + if (dramid > 27) + dramid = 8; + } + + return dramid; +} + +u32 fuse_read_hw_state() +{ + if ((fuse_read_odm(4) & 3) != 3) + return FUSE_NX_HW_STATE_PROD; + else + return FUSE_NX_HW_STATE_DEV; +} + u32 fuse_read_hw_type() { if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) @@ -118,6 +147,7 @@ u32 fuse_read(u32 addr) FUSE(FUSE_ADDR) = addr; FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; fuse_wait_idle(); + return FUSE(FUSE_RDATA); } diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h index d7d5c77..810efd6 100644 --- a/bdk/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -2,6 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 + * 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, @@ -64,9 +65,10 @@ #define FUSE_OPT_X_COORDINATE 0x214 #define FUSE_OPT_Y_COORDINATE 0x218 #define FUSE_GPU_IDDQ_CALIB 0x228 -#define FUSE_RESERVED_ODM28 0x240 #define FUSE_USB_CALIB_EXT 0x350 +#define FUSE_RESERVED_ODM28_T210B01 0x240 + /*! Fuse commands. */ #define FUSE_READ 0x1 #define FUSE_WRITE 0x2 @@ -83,9 +85,17 @@ enum FUSE_NX_HW_TYPE_HOAG }; +enum +{ + FUSE_NX_HW_STATE_PROD, + FUSE_NX_HW_STATE_DEV +}; + void fuse_disable_program(); u32 fuse_read_odm(u32 idx); u32 fuse_read_odm_keygen_rev(); +u32 fuse_read_dramid(bool raw_id); +u32 fuse_read_hw_state(); u32 fuse_read_hw_type(); u8 fuse_count_burnt(u32 val); void fuse_wait_idle(); diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index dd79dc6..1da102f 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -42,6 +42,7 @@ #include #include #include +#include #include extern boot_cfg_t b_cfg; @@ -87,6 +88,7 @@ static void _config_oscillators() CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. } +// The uart is skipped for Copper, Hoag and Calcio. Used in Icosa, Iowa and Aula. static void _config_gpios(bool nx_hoag) { // Clamp inputs when tristated. @@ -263,7 +265,7 @@ static void _config_se_brom() FUSE(FUSE_PRIVATE_KEY3) }; // Set SBK to slot 14. - se_aes_key_set(14, sbk, 0x10); + se_aes_key_set(14, sbk, SE_KEY_128_SIZE); // Lock SBK from being read. se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); @@ -275,7 +277,7 @@ static void _config_se_brom() // This memset needs to happen here, else TZRAM will behave weirdly later on. memset((void *)TZRAM_BASE, 0, 0x10000); PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; - SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; + SE(SE_INT_STATUS_REG) = 0x1F; // Clear all SE interrupts. // Clear the boot reason to avoid problems later PMC(APBDEV_PMC_SCRATCH200) = 0x0; @@ -285,17 +287,21 @@ static void _config_se_brom() static void _config_regulators(bool tegra_t210) { + // Set RTC/AO domain to POR voltage. + if (tegra_t210) + max7762x_regulator_set_voltage(REGULATOR_LDO4, 1000000); + // Disable low battery shutdown monitor. max77620_low_battery_monitor_config(false); // Disable SDMMC1 IO power. gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); - max77620_regulator_enable(REGULATOR_LDO2, 0); + max7762x_regulator_enable(REGULATOR_LDO2, false); 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_ONOFFCNFG1, - BIT(6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + MAX77620_ONOFFCNFG1_RSVD | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. if (tegra_t210) { @@ -313,28 +319,18 @@ static void _config_regulators(bool tegra_t210) (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ // Set vdd_core voltage to 1.125V. - max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); + max7762x_regulator_set_voltage(REGULATOR_SD0, 1125000); - // 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_GPIO6, 2); + // Fix CPU/GPU after L4T warmboot. + max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_DISABLE); + max77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + // Set POR configuration. + max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG); + max77621_config_default(REGULATOR_GPU0, MAX77621_CTRL_POR_CFG); } else // Tegra X1+ set vdd_core voltage to 1.05V. - max77620_regulator_set_voltage(REGULATOR_SD0, 1050000); + max7762x_regulator_set_voltage(REGULATOR_SD0, 1050000); } void hw_init() @@ -373,7 +369,8 @@ void hw_init() #ifdef DEBUG_UART_PORT clock_enable_uart(DEBUG_UART_PORT); - uart_init(DEBUG_UART_PORT, 115200); + uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE); + uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD); #endif // Enable Dynamic Voltage and Frequency Scaling device clock. @@ -391,17 +388,20 @@ void hw_init() //! TODO: Why? Device is NFC MCU on Lite. if (nx_hoag) - max77620_regulator_set_volt_and_flags(REGULATOR_LDO8, 2800000, MAX77620_POWER_MODE_NORMAL); + { + max7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000); + max7762x_regulator_enable(REGULATOR_LDO8, true); + } // Initialize I2C1 for various power related devices. i2c_init(I2C_1); - // Enable charger in case it's disabled. - bq24193_enable_charger(); - // Initialize various regulators based on Erista/Mariko platform. _config_regulators(tegra_t210); + // Enable charger in case it's disabled. + bq24193_enable_charger(); + _config_pmc_scratch(); // Missing from 4.x+ // Set BPMP/SCLK to PLLP_OUT (408MHz). @@ -421,19 +421,18 @@ void hw_init() bpmp_mmu_enable(); } -void hw_reinit_workaround(bool extra_reconfig, u32 magic) +void hw_reinit_workaround(bool coreboot, u32 bl_magic) { // Disable BPMP max clock. bpmp_clk_rate_set(BPMP_CLK_NORMAL); #ifdef NYX - // Deinit touchscreen, 5V regulators and Joy-Con. - touch_power_off(); + // Disable temperature sensor, touchscreen, 5V regulators and Joy-Con. + tmp451_end(); set_fan_duty(0); + touch_power_off(); jc_deinit(); - regulator_disable_5v(REGULATOR_5V_ALL); - clock_disable_uart(UART_B); - clock_disable_uart(UART_C); + regulator_5v_disable(REGULATOR_5V_ALL); #endif // Flush/disable MMU cache and set DRAM clock to 204MHz. @@ -445,10 +444,10 @@ void hw_reinit_workaround(bool extra_reconfig, u32 magic) CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); - if (extra_reconfig) + // Do coreboot mitigations. + if (coreboot) { msleep(10); - PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; clock_disable_cl_dvfs(); @@ -457,13 +456,27 @@ void hw_reinit_workaround(bool extra_reconfig, u32 magic) gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO); gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO); + + // Reinstate SD controller power. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN); } - // Power off display. - display_end(); + // Seamless display or display power off. + switch (bl_magic) + { + case BL_MAGIC_CRBOOT_SLD:; + // Set pwm to 0%, switch to gpio mode and restore pwm duty. + u32 brightness = display_get_backlight_brightness(); + display_backlight_brightness(0, 1000); + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_GPIO); + display_backlight_brightness(brightness, 0); + break; + default: + display_end(); + } // Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits. - if (magic == 0xBAADF00D) + if (bl_magic == BL_MAGIC_BROKEN_HWI) { CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_USBD); sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0); diff --git a/bdk/soc/hw_init.h b/bdk/soc/hw_init.h index ff9ae4a..a1b2dfc 100644 --- a/bdk/soc/hw_init.h +++ b/bdk/soc/hw_init.h @@ -20,8 +20,11 @@ #include +#define BL_MAGIC_CRBOOT_SLD 0x30444C53 // SLD0, seamless display type 0. +#define BL_MAGIC_BROKEN_HWI 0xBAADF00D // Broken hwinit. + void hw_init(); -void hw_reinit_workaround(bool extra_reconfig, u32 magic); +void hw_reinit_workaround(bool coreboot, u32 magic); u32 hw_get_chip_id(); #endif diff --git a/bdk/soc/i2c.c b/bdk/soc/i2c.c index 099a182..0906adc 100644 --- a/bdk/soc/i2c.c +++ b/bdk/soc/i2c.c @@ -136,10 +136,10 @@ static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size) // Initiate transaction on normal mode. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; - u32 timeout = get_tmr_ms() + 400; // Actual for max 8 bytes at 100KHz is 0.74ms. + u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms. while (base[I2C_STATUS] & I2C_STATUS_BUSY) { - if (get_tmr_ms() > timeout) + if (get_tmr_us() > timeout) return 0; } @@ -168,10 +168,10 @@ static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) // Initiate transaction on normal mode. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; - u32 timeout = get_tmr_ms() + 400; // Actual for max 8 bytes at 100KHz is 0.74ms. + u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms. while (base[I2C_STATUS] & I2C_STATUS_BUSY) { - if (get_tmr_ms() > timeout) + if (get_tmr_us() > timeout) return 0; } diff --git a/bdk/soc/irq.c b/bdk/soc/irq.c index 4fb39ca..e2f925c 100644 --- a/bdk/soc/irq.c +++ b/bdk/soc/irq.c @@ -133,6 +133,10 @@ static irq_status_t _irq_handle_source(u32 irq) } } + // Do not re-enable if not handled. + if (status == IRQ_NONE) + return status; + if (irqs[idx].flags & IRQ_FLAG_ONE_OFF) irq_free(irq); else @@ -148,7 +152,9 @@ void irq_handler() if (!irq_init_done) { + _irq_disable_source(irq); _irq_ack_source(irq); + return; } @@ -156,9 +162,10 @@ void irq_handler() int err = _irq_handle_source(irq); - //TODO: disable if unhandhled. if (err == IRQ_NONE) - gfx_printf("Unhandled IRQ: %d\n", irq); + { + DPRINTF("Unhandled IRQ got disabled: %d!\n", irq); + } } static void _irq_init() @@ -170,6 +177,9 @@ static void _irq_init() void irq_end() { + if (!irq_init_done) + return; + _irq_free_all(); irq_disable_cpu_irq_exceptions(); irq_init_done = false; diff --git a/bdk/soc/pmc.c b/bdk/soc/pmc.c index 62caa22..aa86cb7 100644 --- a/bdk/soc/pmc.c +++ b/bdk/soc/pmc.c @@ -14,11 +14,69 @@ * along with this program. If not, see . */ +#include #include #include #include -int pmc_enable_partition(u32 part, int enable) +void pmc_scratch_lock(pmc_sec_lock_t lock_mask) +{ + // Lock Private key disable, Fuse write enable, MC carveout, Warmboot PA id and Warmboot address. + if (lock_mask & PMC_SEC_LOCK_MISC) + { + PMC(APBDEV_PMC_SEC_DISABLE) |= 0x700FF0; // RW lock: 0-3. + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0xFC000000; // RW lock: 21-23. + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0x3F0FFF00; // RW lock: 28-33, 36-38. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xC000000; // RW lock: 85. + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF00FF00; // RW lock: 108-111, 116-119. + + // SE2 context. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + { + PMC(APBDEV_PMC_SEC_DISABLE9) |= 0x3FF; // RW lock: 120-124. (0xB38) + PMC(APBDEV_PMC_SEC_DISABLE10) = 0xFFFFFFFF; // RW lock: 135-150. + } + } + + if (lock_mask & PMC_SEC_LOCK_LP0_PARAMS) + { + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF; // RW lock: 8-15, 17-20. + PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF; // RW lock: 40-50, 52-54. + PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF; // RW lock: 56-71. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F; // RW lock: 72-73, 79-84, 86-87. + PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF; // RW lock: 88-98. + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF; // RW lock: 104-107. + } + + if (lock_mask & PMC_SEC_LOCK_RST_VECTOR) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xF00000; // RW lock: 34-35. + + if (lock_mask & PMC_SEC_LOCK_CARVEOUTS) + { + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x30000; // RW lock: 16. + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xC0000000; // RW lock: 39. + PMC(APBDEV_PMC_SEC_DISABLE4) |= 0xC0C00000; // RW lock: 51, 55. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0x3FF0; // RW lock: 74-78. + PMC(APBDEV_PMC_SEC_DISABLE7) |= 0xFFC00000; // RW lock: 99-103. + } + + if (lock_mask & PMC_SEC_LOCK_TZ_CMAC_W) + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0x550000; // W lock: 112-115. + + if (lock_mask & PMC_SEC_LOCK_TZ_CMAC_R) + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xAA0000; // R lock: 112-115. + + if (lock_mask & PMC_SEC_LOCK_TZ_KEK_W) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0x55; // W lock: 24-27. + + if (lock_mask & PMC_SEC_LOCK_TZ_KEK_R) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xAA; // R lock: 24-27. + + if (lock_mask & PMC_SEC_LOCK_SE_SRK) + PMC(APBDEV_PMC_SEC_DISABLE) |= 0xFF000; // RW lock: 4-7 +} + +int pmc_enable_partition(pmc_power_rail_t part, u32 enable) { u32 part_mask = BIT(part); u32 desired_state = enable << part; diff --git a/bdk/soc/pmc.h b/bdk/soc/pmc.h index c27d937..42bd869 100644 --- a/bdk/soc/pmc.h +++ b/bdk/soc/pmc.h @@ -91,6 +91,8 @@ #define APBDEV_PMC_SEC_DISABLE6 0x5B8 #define APBDEV_PMC_SEC_DISABLE7 0x5BC #define APBDEV_PMC_SEC_DISABLE8 0x5C0 +#define APBDEV_PMC_SEC_DISABLE9 0x5C4 +#define APBDEV_PMC_SEC_DISABLE10 0x5C8 #define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH200 0x840 @@ -98,6 +100,54 @@ #define APBDEV_PMC_TZRAM_SEC_DISABLE 0xBEC #define APBDEV_PMC_TZRAM_NON_SEC_DISABLE 0xBF0 -int pmc_enable_partition(u32 part, int enable); +typedef enum _pmc_sec_lock_t +{ + PMC_SEC_LOCK_MISC = BIT(0), + PMC_SEC_LOCK_LP0_PARAMS = BIT(1), + PMC_SEC_LOCK_RST_VECTOR = BIT(2), + PMC_SEC_LOCK_CARVEOUTS = BIT(3), + PMC_SEC_LOCK_TZ_CMAC_W = BIT(4), + PMC_SEC_LOCK_TZ_CMAC_R = BIT(5), + PMC_SEC_LOCK_TZ_KEK_W = BIT(6), + PMC_SEC_LOCK_TZ_KEK_R = BIT(7), + PMC_SEC_LOCK_SE_SRK = BIT(8), +} pmc_sec_lock_t; + +typedef enum _pmc_power_rail_t +{ + POWER_RAIL_CRAIL = 0, + POWER_RAIL_3D0 = 1, + POWER_RAIL_VENC = 2, + POWER_RAIL_PCIE = 3, + POWER_RAIL_VDEC = 4, + POWER_RAIL_L2C = 5, + POWER_RAIL_MPE = 6, + POWER_RAIL_HEG = 7, + POWER_RAIL_SATA = 8, + POWER_RAIL_CE1 = 9, + POWER_RAIL_CE2 = 10, + POWER_RAIL_CE3 = 11, + POWER_RAIL_CELP = 12, + POWER_RAIL_3D1 = 13, + POWER_RAIL_CE0 = 14, + POWER_RAIL_C0NC = 15, + POWER_RAIL_C1NC = 16, + POWER_RAIL_SOR = 17, + POWER_RAIL_DIS = 18, + POWER_RAIL_DISB = 19, + POWER_RAIL_XUSBA = 20, + POWER_RAIL_XUSBB = 21, + POWER_RAIL_XUSBC = 22, + POWER_RAIL_VIC = 23, + POWER_RAIL_IRAM = 24, + POWER_RAIL_NVDEC = 25, + POWER_RAIL_NVJPG = 26, + POWER_RAIL_AUD = 27, + POWER_RAIL_DFD = 28, + POWER_RAIL_VE2 = 29 +} pmc_power_rail_t; + +void pmc_scratch_lock(pmc_sec_lock_t lock_mask); +int pmc_enable_partition(pmc_power_rail_t part, u32 enable); #endif diff --git a/bdk/soc/uart.c b/bdk/soc/uart.c index 75e18b8..582bca1 100644 --- a/bdk/soc/uart.c +++ b/bdk/soc/uart.c @@ -122,7 +122,12 @@ u32 uart_get_IIR(u32 idx) { uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - return uart->UART_IIR_FCR; + u32 iir = uart->UART_IIR_FCR & UART_IIR_INT_MASK; + + if (iir & UART_IIR_NO_INT) + return 0; + else + return ((iir >> 1) + 1); // Return encoded interrupt. } void uart_set_IIR(u32 idx) diff --git a/bdk/soc/uart.h b/bdk/soc/uart.h index 809192a..6a4c073 100644 --- a/bdk/soc/uart.h +++ b/bdk/soc/uart.h @@ -54,6 +54,17 @@ #define UART_IIR_FCR_RX_CLR 0x2 #define UART_IIR_FCR_EN_FIFO 0x1 +#define UART_IIR_NO_INT BIT(0) +#define UART_IIR_INT_MASK 0xF +/* Custom returned interrupt results. Actual interrupts are -1 */ +#define UART_IIR_NOI 0 // No interrupt. +#define UART_IIR_MSI 1 // Modem status interrupt. +#define UART_IIR_THRI 2 // Transmitter holding register empty. +#define UART_IIR_RDI 3 // Receiver data interrupt. +#define UART_IIR_ERROR 4 // Overrun Error, Parity Error, Framing Error, Break. +#define UART_IIR_REDI 5 // Receiver end of data interrupt. +#define UART_IIR_RDTI 7 // Receiver data timeout interrupt. + #define UART_MCR_RTS 0x2 #define UART_MCR_DTR 0x1 diff --git a/bdk/storage/mmc.h b/bdk/storage/mmc.h index efa9e10..fc6c2f8 100644 --- a/bdk/storage/mmc.h +++ b/bdk/storage/mmc.h @@ -84,6 +84,11 @@ #define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ +#define MMC_VENDOR_60_CMD 60 /* Vendor Defined */ +#define MMC_VENDOR_61_CMD 61 /* Vendor Defined */ +#define MMC_VENDOR_62_CMD 62 /* Vendor Defined */ +#define MMC_VENDOR_63_CMD 63 /* Vendor Defined */ + /* class 11 */ #define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */ #define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */ @@ -142,7 +147,10 @@ c : clear by read #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +#define R1_SKIP_STATE_CHECK (1 << 4) /* Custom state to skip expected state check */ +#define R1_AKE_SEQ_ERROR (1 << 3) +/* R1_CURRENT_STATE 12:9 */ #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 @@ -179,7 +187,10 @@ c : clear by read /* * OCR bits are mostly in host.h */ -#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ +#define MMC_CARD_VDD_18 (1 << 7) /* Card VDD voltage 1.8 */ +#define MMC_CARD_VDD_27_34 (0x7F << 15) /* Card VDD voltage 2.7 ~ 3.4 */ +#define MMC_CARD_CCS (1 << 30) /* Card Capacity status bit */ +#define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */ /* * Card Command Classes (CCC) @@ -241,6 +252,7 @@ c : clear by read #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ #define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_MAX_ENH_SIZE_MULT 157 /* RO, 3 bytes */ #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ #define EXT_CSD_HPI_MGMT 161 /* R/W */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ diff --git a/bdk/storage/nx_sd.h b/bdk/storage/nx_sd.h index bc4c2d4..e2b703f 100644 --- a/bdk/storage/nx_sd.h +++ b/bdk/storage/nx_sd.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 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, @@ -45,12 +45,15 @@ extern FATFS sd_fs; void sd_error_count_increment(u8 type); u16 *sd_get_error_count(); bool sd_get_card_removed(); +bool sd_get_card_initialized(); +bool sd_get_card_mounted(); 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_end(); +bool sd_is_gpt(); void *sd_file_read(const char *path, u32 *fsize); int sd_save_to_file(void *buf, u32 size, const char *filename); diff --git a/bdk/storage/ramdisk.c b/bdk/storage/ramdisk.c index e7b7c01..315075d 100644 --- a/bdk/storage/ramdisk.c +++ b/bdk/storage/ramdisk.c @@ -1,7 +1,7 @@ /* * Ramdisk driver for Tegra X1 * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,23 +19,40 @@ #include #include "ramdisk.h" +#include #include #include #include -int ram_disk_init(FATFS *ram_fs) +static u32 disk_size = 0; + +int ram_disk_init(FATFS *ram_fs, u32 ramdisk_size) { - int res; - u8 *buf = malloc(0x400000); + int res = 0; + disk_size = ramdisk_size; - f_mount(NULL, "ram:", 1); // Unmount ramdisk. + // If ramdisk is not raw, format it. + if (ram_fs) + { + u8 *buf = malloc(0x400000); - res = f_mkfs("ram:", FM_EXFAT, RAMDISK_CLUSTER_SZ, buf, 0x400000); // Format as exFAT w/ 32KB cluster. - if (!res) - res = f_mount(ram_fs, "ram:", 1); // Mount ramdisk. + // Set ramdisk size. + ramdisk_size >>= 9; + disk_set_info(DRIVE_RAM, SET_SECTOR_COUNT, &ramdisk_size); - free(buf); + // Unmount ramdisk. + f_mount(NULL, "ram:", 1); + + // Format as exFAT w/ 32KB cluster with no MBR. + res = f_mkfs("ram:", FM_EXFAT | FM_SFD, RAMDISK_CLUSTER_SZ, buf, 0x400000); + + // Mount ramdisk. + if (!res) + res = f_mount(ram_fs, "ram:", 1); + + free(buf); + } return res; } @@ -45,7 +62,7 @@ int ram_disk_read(u32 sector, u32 sector_count, void *buf) u32 sector_off = RAM_DISK_ADDR + (sector << 9); u32 bytes_count = sector_count << 9; - if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + if ((sector_off - RAM_DISK_ADDR) > disk_size) return 1; memcpy(buf, (void *)sector_off, bytes_count); @@ -58,7 +75,7 @@ int ram_disk_write(u32 sector, u32 sector_count, const void *buf) u32 sector_off = RAM_DISK_ADDR + (sector << 9); u32 bytes_count = sector_count << 9; - if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + if ((sector_off - RAM_DISK_ADDR) > disk_size) return 1; memcpy((void *)sector_off, buf, bytes_count); diff --git a/bdk/storage/ramdisk.h b/bdk/storage/ramdisk.h index ef43bb5..e625235 100644 --- a/bdk/storage/ramdisk.h +++ b/bdk/storage/ramdisk.h @@ -1,7 +1,7 @@ /* * Ramdisk driver for Tegra X1 * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,7 +23,7 @@ #define RAMDISK_CLUSTER_SZ 32768 -int ram_disk_init(FATFS *ram_fs); +int ram_disk_init(FATFS *ram_fs, u32 ramdisk_size); int ram_disk_read(u32 sector, u32 sector_count, void *buf); int ram_disk_write(u32 sector, u32 sector_count, const void *buf); diff --git a/bdk/storage/sd.h b/bdk/storage/sd.h index a780ec8..22d3359 100644 --- a/bdk/storage/sd.h +++ b/bdk/storage/sd.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2021 CTCaer * * 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 @@ -14,58 +14,79 @@ /* SD commands type argument response */ /* class 0 */ /* This is basically the same command as for MMC with some quirks. */ -#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ -#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ -#define SD_SWITCH_VOLTAGE 11 /* ac R1 */ - +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ +#define SD_SWITCH_VOLTAGE 11 /* ac R1 */ /* class 10 */ -#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ - +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* class 5 */ -#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */ -#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */ /* Application commands */ -#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ -#define SD_APP_SD_STATUS 13 /* adtc R1 */ -#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ -#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ -#define SD_APP_SET_CLR_CARD_DETECT 42 -#define SD_APP_SEND_SCR 51 /* adtc R1 */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SD_STATUS 13 /* adtc R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SET_CLR_CARD_DETECT 42 /* adtc R1 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* Application secure commands */ +#define SD_APP_SECURE_READ_MULTI_BLOCK 18 /* adtc R1 */ +#define SD_APP_SECURE_WRITE_MULTI_BLOCK 25 /* adtc R1 */ +#define SD_APP_SECURE_WRITE_MKB 26 /* adtc R1 */ +#define SD_APP_SECURE_ERASE 38 /* adtc R1b */ +#define SD_APP_GET_MKB 43 /* adtc [31:0] See below R1 */ +#define SD_APP_GET_MID 44 /* adtc R1 */ +#define SD_APP_SET_CER_RN1 45 /* adtc R1 */ +#define SD_APP_GET_CER_RN2 46 /* adtc R1 */ +#define SD_APP_SET_CER_RES2 47 /* adtc R1 */ +#define SD_APP_GET_CER_RES1 48 /* adtc R1 */ +#define SD_APP_CHANGE_SECURE_AREA 49 /* adtc R1b */ /* OCR bit definitions */ +#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ +#define SD_VHD_27_36 (1 << 8) /* VDD voltage 2.7 ~ 3.6 */ +#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ +#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ #define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ #define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ #define SD_OCR_XPC (1 << 28) /* SDXC power control */ #define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ -#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ -#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ -#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ +#define SD_OCR_BUSY (1 << 31) /* Card Power up Status */ /* -* SD_SWITCH argument format: -* -* [31] Check (0) or switch (1) -* [30:24] Reserved (0) -* [23:20] Function group 6 -* [19:16] Function group 5 -* [15:12] Function group 4 -* [11:8] Function group 3 -* [7:4] Function group 2 -* [3:0] Function group 1 -*/ + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ /* -* SD_SEND_IF_COND argument format: -* -* [31:12] Reserved (0) -* [11:8] Host Voltage Supply Flags -* [7:0] Check Pattern (0xAA) -*/ + * SD_SEND_IF_COND argument format: + * + * [31:12] Reserved (0) + * [11:8] Host Voltage Supply Flags + * [7:0] Check Pattern (0xAA) + */ /* -* SCR field definitions -*/ + * SD_APP_GET_MKB argument format: + * + * [31:24] Number of blocks to read (512 block size) + * [23:16] MKB ID + * [15:0] Block offset + */ + +/* + * SCR field definitions + */ #define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ #define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ #define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ @@ -73,14 +94,14 @@ #define SD_SCR_BUS_WIDTH_4 (1<<2) /* -* SD bus widths -*/ + * SD bus widths + */ #define SD_BUS_WIDTH_1 0 #define SD_BUS_WIDTH_4 2 /* -* SD bus speeds -*/ + * SD bus speeds + */ #define UHS_SDR12_BUS_SPEED 0 #define HIGH_SPEED_BUS_SPEED 1 #define UHS_SDR25_BUS_SPEED 1 @@ -110,19 +131,19 @@ #define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800) /* -* SD_SWITCH mode -*/ + * SD_SWITCH mode + */ #define SD_SWITCH_CHECK 0 #define SD_SWITCH_SET 1 /* -* SD_SWITCH function groups -*/ + * SD_SWITCH function groups + */ #define SD_SWITCH_GRP_ACCESS 0 /* -* SD_SWITCH access modes -*/ + * SD_SWITCH access modes + */ #define SD_SWITCH_ACCESS_DEF 0 #define SD_SWITCH_ACCESS_HS 1 diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c index 43f837d..54b19de 100644 --- a/bdk/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -42,10 +42,10 @@ static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) } /* -* Common functions for SD and MMC. -*/ + * Common functions for SD and MMC. + */ -static int _sdmmc_storage_check_result(u32 res) +static int _sdmmc_storage_check_card_status(u32 res) { //Error mask: //TODO: R1_SWITCH_ERROR can be skipped for certain card types. @@ -66,15 +66,15 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, cmd, arg, SDMMC_RSP_TYPE_1, check_busy); - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) return 0; sdmmc_get_rsp(storage->sdmmc, resp, 4, SDMMC_RSP_TYPE_1); if (mask) *resp &= ~mask; - if (_sdmmc_storage_check_result(*resp)) - if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) + if (_sdmmc_storage_check_card_status(*resp)) + if (expected_state == R1_SKIP_STATE_CHECK || R1_CURRENT_STATE(*resp) == expected_state) return 1; return 0; @@ -88,37 +88,37 @@ static int _sdmmc_storage_execute_cmd_type1(sdmmc_storage_t *storage, u32 cmd, u static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) { - sdmmc_cmd_t cmd; - sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); - return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); + return sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL); } -static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) +static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage) { - sdmmc_cmd_t cmd; - sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); - if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) return 0; - sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_cid, 16, SDMMC_RSP_TYPE_2); return 1; } static int _sdmmc_storage_select_card(sdmmc_storage_t *storage) { - return _sdmmc_storage_execute_cmd_type1(storage, MMC_SELECT_CARD, storage->rca << 16, 1, 0x10); + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SELECT_CARD, storage->rca << 16, 1, R1_SKIP_STATE_CHECK); } -static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) +static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) return 0; - sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_csd, 16, SDMMC_RSP_TYPE_2); return 1; } @@ -145,6 +145,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out sdmmc_cmd_t cmdbuf; sdmmc_req_t reqbuf; + // If SDSC convert block address to byte address. + if (!storage->has_sector_access) + sector <<= 9; + sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); reqbuf.buf = buf; @@ -152,7 +156,7 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out reqbuf.blksize = 512; reqbuf.is_write = is_write; reqbuf.is_multi_block = 1; - reqbuf.is_auto_cmd12 = 1; + reqbuf.is_auto_stop_trn = 1; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) { @@ -288,25 +292,25 @@ int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, v static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power) { - sdmmc_cmd_t cmd; + sdmmc_cmd_t cmdbuf; u32 arg = 0; switch (power) { case SDMMC_POWER_1_8: - arg = SD_OCR_CCS | SD_OCR_VDD_18; + arg = MMC_CARD_CCS | MMC_CARD_VDD_18; break; case SDMMC_POWER_3_3: - arg = SD_OCR_CCS | SD_OCR_VDD_27_34; + arg = MMC_CARD_CCS | MMC_CARD_VDD_27_34; break; default: return 0; } - sdmmc_init_cmd(&cmd, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); - if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) + sdmmc_init_cmd(&cmdbuf, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) return 0; return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3); @@ -316,15 +320,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) { u32 timeout = get_tmr_ms() + 1500; - while (1) + while (true) { u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; + // Check if power up is done. if (cond & MMC_CARD_BUSY) { - if (cond & SD_OCR_CCS) + // Check if card is high capacity. + if (cond & MMC_CARD_CCS) storage->has_sector_access = 1; return 1; @@ -340,7 +346,7 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) static int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage) { - return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, 0x10); + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, R1_SKIP_STATE_CHECK); } static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) @@ -362,7 +368,6 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2); storage->cid.oemid = unstuff_bits(raw_cid, 104, 8); storage->cid.prv = unstuff_bits(raw_cid, 48, 8); storage->cid.serial = unstuff_bits(raw_cid, 16, 32); @@ -390,13 +395,14 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) { - u32 *raw_csd = (u32 *)&(storage->raw_csd); + u32 *raw_csd = (u32 *)storage->raw_csd; storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); storage->csd.structure = unstuff_bits(raw_csd, 126, 2); storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); + storage->sec_cnt = storage->csd.capacity; } static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) @@ -407,16 +413,26 @@ static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; - storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT]; - storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; - storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; - storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; + //storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; + //storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; + //storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; storage->ext_csd.pre_eol_info = buf[EXT_CSD_PRE_EOL_INFO]; storage->ext_csd.dev_life_est_a = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; storage->ext_csd.dev_life_est_b = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; - storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; + storage->ext_csd.cache_size = + buf[EXT_CSD_CACHE_SIZE] | + (buf[EXT_CSD_CACHE_SIZE + 1] << 8) | + (buf[EXT_CSD_CACHE_SIZE + 2] << 16) | + (buf[EXT_CSD_CACHE_SIZE + 3] << 24); + storage->ext_csd.max_enh_mult = + (buf[EXT_CSD_MAX_ENH_SIZE_MULT] | + (buf[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8) | + (buf[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16)) * + buf[EXT_CSD_HC_WP_GRP_SIZE] * buf[EXT_CSD_HC_ERASE_GRP_SIZE]; + + storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; } static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) @@ -430,21 +446,21 @@ static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); _mmc_storage_parse_ext_csd(storage, buf); - return _sdmmc_storage_check_result(tmp); + return _sdmmc_storage_check_card_status(tmp); } static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg) { - return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, 0x10); + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK); } static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) @@ -559,19 +575,21 @@ out: return 1; } +/* static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) { - if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_AUTO_BKOPS_MASK))) return 0; return _sdmmc_storage_check_status(storage); } +*/ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; - storage->rca = 2; //TODO: this could be a config item. + storage->rca = 2; // Set default device address. This could be a config item. if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_POWER_SAVE_DISABLE)) return 0; @@ -587,7 +605,7 @@ DPRINTF("[MMC] went to idle state\n"); return 0; DPRINTF("[MMC] got op cond\n"); - if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) + if (!_sdmmc_storage_get_cid(storage)) return 0; DPRINTF("[MMC] got cid\n"); @@ -595,7 +613,7 @@ DPRINTF("[MMC] got cid\n"); return 0; DPRINTF("[MMC] set relative addr\n"); - if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) + if (!_sdmmc_storage_get_csd(storage)) return 0; DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); @@ -612,13 +630,9 @@ DPRINTF("[MMC] card selected\n"); return 0; DPRINTF("[MMC] set blocklen to 512\n"); - u32 *csd = (u32 *)storage->raw_csd; - //Check system specification version, only version 4.0 and later support below features. - if (unstuff_bits(csd, 122, 4) < CSD_SPEC_VER_4) - { - storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2); + // Check system specification version, only version 4.0 and later support below features. + if (storage->csd.mmca_vsn < CSD_SPEC_VER_4) return 1; - } if (!_mmc_storage_switch_buswidth(storage, bus_width)) return 0; @@ -628,21 +642,20 @@ DPRINTF("[MMC] switched buswidth\n"); return 0; 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); - /* 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(). - Additionally this works only when we put the device in idle mode which we don't after enabling it. */ - if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2)) +/* + if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_AUTO_BKOPS_MASK)) { _mmc_storage_enable_bkops(storage); DPRINTF("[MMC] BKOPS enabled\n"); } +*/ if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; -DPRINTF("[MMC] succesfully switched to HS mode\n"); +DPRINTF("[MMC] successfully switched to HS mode\n"); sdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE); @@ -665,16 +678,16 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) } /* -* SD specific functions. -*/ + * SD specific functions. + */ -static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_state, u32 mask, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_state, u32 mask, sdmmc_cmd_t *cmdbuf, sdmmc_req_t *req, u32 *blkcnt_out) { u32 tmp; if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) return 0; - return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); + return sdmmc_execute_cmd(storage->sdmmc, cmdbuf, req, blkcnt_out); } static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state) @@ -685,60 +698,70 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); } -static int _sd_storage_send_if_cond(sdmmc_storage_t *storage) +static int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc) { sdmmc_cmd_t cmdbuf; - sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, 0x1AA, SDMMC_RSP_TYPE_5, 0); - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) - return 1; // The SD Card is version 1.X + u16 vhd_pattern = SD_VHD_27_36 | 0xAA; + sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_5, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) + { + *is_sdsc = 1; // The SD Card is version 1.X + return 1; + } + // For Card version >= 2.0, parse results. u32 resp = 0; - if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) - return 2; + sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5); - return (resp & 0xFF) == 0xAA ? 0 : 2; + // Check if VHD was accepted and pattern was properly returned. + if ((resp & 0xFFF) == vhd_pattern) + return 1; + + return 0; } -static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int bus_low_voltage_support) +static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, bool is_sdsc, int bus_uhs_support) { sdmmc_cmd_t cmdbuf; // Support for Current > 150mA - u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0; + u32 arg = !is_sdsc ? SD_OCR_XPC : 0; // Support for handling block-addressed SDHC cards - arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; + arg |= !is_sdsc ? SD_OCR_CCS : 0; // Support for 1.8V - arg |= (bus_low_voltage_support & ~is_version_1 & 1) ? SD_OCR_S18R : 0; + arg |= (bus_uhs_support && !is_sdsc) ? SD_OCR_S18R : 0; // This is needed for most cards. Do not set bit7 even if 1.8V is supported. arg |= SD_OCR_VDD_32_33; sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); - if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) + if (!_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL)) return 0; return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } -static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int bus_low_voltage_support) +static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support) { u32 timeout = get_tmr_ms() + 1500; - while (1) + while (true) { u32 cond = 0; - if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, bus_low_voltage_support)) + if (!_sd_storage_get_op_cond_once(storage, &cond, is_sdsc, bus_uhs_support)) break; - if (cond & MMC_CARD_BUSY) - { -DPRINTF("[SD] cond: %08X, lv: %d\n", cond, bus_low_voltage_support); + // Check if power up is done. + if (cond & SD_OCR_BUSY) + { +DPRINTF("[SD] op cond: %08X, lv: %d\n", cond, bus_uhs_support); + + // Check if card is high capacity. if (cond & SD_OCR_CCS) storage->has_sector_access = 1; // Check if card supports 1.8V signaling. - if (cond & SD_ROCR_S18A && bus_low_voltage_support) + if (cond & SD_ROCR_S18A && bus_uhs_support) { - //The low voltage regulator configuration is valid for SDMMC1 only. - if (storage->sdmmc->id == SDMMC_1 && - _sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) + // Switch to 1.8V signaling. + if (_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) { if (!sdmmc_enable_low_voltage(storage->sdmmc)) return 0; @@ -769,9 +792,9 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage) u32 timeout = get_tmr_ms() + 1500; - while (1) + while (true) { - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) break; u32 resp = 0; @@ -802,8 +825,9 @@ static void _sd_storage_parse_scr(sdmmc_storage_t *storage) storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); storage->scr.bus_widths = unstuff_bits(resp, 48, 4); + + /* If v2.0 is supported, check if Physical Layer Spec v3.0 is supported */ if (storage->scr.sda_vsn == SCR_SPEC_VER_2) - /* Check if Physical Layer Spec v3.0 is supported */ storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); if (storage->scr.sda_spec3) storage->scr.cmds = unstuff_bits(resp, 32, 2); @@ -820,9 +844,9 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; - if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0)) + if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL)) return 0; u32 tmp = 0; @@ -838,7 +862,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) _sd_storage_parse_scr(storage); //gfx_hexdump(0, storage->raw_scr, 8); - return _sdmmc_storage_check_result(tmp); + return _sdmmc_storage_check_card_status(tmp); } int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) @@ -852,14 +876,14 @@ int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); - return _sdmmc_storage_check_result(tmp); + return _sdmmc_storage_check_card_status(tmp); } int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, u32 arg) @@ -876,14 +900,14 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); - return _sdmmc_storage_check_result(tmp); + return _sdmmc_storage_check_card_status(tmp); } void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf) @@ -1057,41 +1081,64 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25); } +u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage) +{ + u32 au_size = storage->ssr.uhs_au_size; + + if (!au_size) + au_size = storage->ssr.au_size; + + if (au_size <= 10) + { + u32 shift = au_size; + au_size = shift ? 8 : 0; + au_size <<= shift; + } + else + { + switch (au_size) + { + case 11: + au_size = 12288; + break; + case 12: + au_size = 16384; + break; + case 13: + au_size = 24576; + break; + case 14: + au_size = 32768; + break; + case 15: + au_size = 65536; + break; + } + } + + return au_size; +} + static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) { - // unstuff_bits supports only 4 u32 so break into 2 x 16byte groups + // unstuff_bits supports only 4 u32 so break into 2 x u32x4 groups. u32 raw_ssr1[4]; u32 raw_ssr2[4]; - raw_ssr1[3] = *(u32 *)&storage->raw_ssr[12]; - raw_ssr1[2] = *(u32 *)&storage->raw_ssr[8]; - raw_ssr1[1] = *(u32 *)&storage->raw_ssr[4]; - raw_ssr1[0] = *(u32 *)&storage->raw_ssr[0]; - - raw_ssr2[3] = *(u32 *)&storage->raw_ssr[28]; - raw_ssr2[2] = *(u32 *)&storage->raw_ssr[24]; - raw_ssr2[1] = *(u32 *)&storage->raw_ssr[20]; - raw_ssr2[0] = *(u32 *)&storage->raw_ssr[16]; + memcpy(raw_ssr1, &storage->raw_ssr[0], 16); + memcpy(raw_ssr2, &storage->raw_ssr[16], 16); storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1; storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448 - 384, 32); - switch(unstuff_bits(raw_ssr1, 440 - 384, 8)) + u32 speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); + switch(speed_class) { case 0: - storage->ssr.speed_class = 0; - break; - case 1: - storage->ssr.speed_class = 2; - break; - case 2: - storage->ssr.speed_class = 4; - break; - case 3: - storage->ssr.speed_class = 6; + storage->ssr.speed_class = speed_class << 1; break; case 4: @@ -1099,16 +1146,18 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) break; default: - storage->ssr.speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); + storage->ssr.speed_class = speed_class; break; } - storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4); + storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4); storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8); + storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4); - storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4); + storage->ssr.au_size = unstuff_bits(raw_ssr1, 428 - 384, 4); + storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392 - 384, 4); } -static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) +int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, SDMMC_RSP_TYPE_1, 0); @@ -1119,49 +1168,51 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; if (!(storage->csd.cmdclass & CCC_APP_SPEC)) { -DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); +DPRINTF("[SD] ssr: Not supported\n"); return 0; } - if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0)) + if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); - //Prepare buffer for unstuff_bits - for (int i = 0; i < 64; i+=4) + + // Convert buffer to LE. + for (int i = 0; i < 64; i += 4) { storage->raw_ssr[i + 3] = buf[i]; storage->raw_ssr[i + 2] = buf[i + 1]; storage->raw_ssr[i + 1] = buf[i + 2]; storage->raw_ssr[i] = buf[i + 3]; } + _sd_storage_parse_ssr(storage); //gfx_hexdump(0, storage->raw_ssr, 64); - return _sdmmc_storage_check_result(tmp); + return _sdmmc_storage_check_card_status(tmp); } static void _sd_storage_parse_cid(sdmmc_storage_t *storage) { u32 *raw_cid = (u32 *)&(storage->raw_cid); - storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); - storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); - storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); - storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); - storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); - storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); - storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); - storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); - storage->cid.serial = unstuff_bits(raw_cid, 24, 32); - storage->cid.month = unstuff_bits(raw_cid, 8, 4); - storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; + storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); + storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); + storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); + storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); + storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); + storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); + storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); + storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); + storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); + storage->cid.serial = unstuff_bits(raw_cid, 24, 32); + storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; + storage->cid.month = unstuff_bits(raw_cid, 8, 4); } static void _sd_storage_parse_csd(sdmmc_storage_t *storage) @@ -1176,6 +1227,7 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) { case 0: storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); + storage->csd.capacity <<= unstuff_bits(raw_csd, 80, 4) - 9; // Convert native block size to LBA 512B. break; case 1: @@ -1183,10 +1235,16 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) storage->csd.capacity = storage->csd.c_size << 10; storage->csd.read_blkbits = 9; break; + + default: +DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); + break; } + + storage->sec_cnt = storage->csd.capacity; } -static bool _sdmmc_storage_get_low_voltage_support(u32 bus_width, u32 type) +static bool _sdmmc_storage_get_bus_uhs_support(u32 bus_width, u32 type) { switch (type) { @@ -1213,8 +1271,10 @@ void sdmmc_storage_init_wait_sd() int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { - int is_version_1 = 0; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + u32 tmp = 0; + int is_sdsc = 0; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + bool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type); DPRINTF("[SD] init: bus: %d, type: %d\n", bus_width, type); @@ -1234,18 +1294,15 @@ DPRINTF("[SD] after init\n"); return 0; DPRINTF("[SD] went to idle state\n"); - is_version_1 = _sd_storage_send_if_cond(storage); - if (is_version_1 == 2) + if (!_sd_storage_send_if_cond(storage, &is_sdsc)) return 0; DPRINTF("[SD] after send if cond\n"); - bool bus_low_voltage_support = _sdmmc_storage_get_low_voltage_support(bus_width, type); - - if (!_sd_storage_get_op_cond(storage, is_version_1, bus_low_voltage_support)) + if (!_sd_storage_get_op_cond(storage, is_sdsc, bus_uhs_support)) return 0; DPRINTF("[SD] got op cond\n"); - if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) + if (!_sdmmc_storage_get_cid(storage)) return 0; DPRINTF("[SD] got cid\n"); _sd_storage_parse_cid(storage); @@ -1254,30 +1311,16 @@ DPRINTF("[SD] got cid\n"); return 0; DPRINTF("[SD] got rca (= %04X)\n", storage->rca); - if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) + if (!_sdmmc_storage_get_csd(storage)) return 0; DPRINTF("[SD] got csd\n"); - - //Parse CSD. _sd_storage_parse_csd(storage); - switch (storage->csd.structure) - { - case 0: - storage->sec_cnt = storage->csd.capacity; - break; - case 1: - storage->sec_cnt = storage->csd.c_size << 10; - break; - default: -DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); - break; - } if (!storage->is_low_voltage) { if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12)) return 0; -DPRINTF("[SD] after setup clock\n"); +DPRINTF("[SD] after setup default clock\n"); } if (!_sdmmc_storage_select_card(storage)) @@ -1288,19 +1331,17 @@ DPRINTF("[SD] card selected\n"); return 0; DPRINTF("[SD] set blocklen to 512\n"); - u32 tmp = 0; + // Disconnect Card Detect resistor from DAT3. if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) return 0; DPRINTF("[SD] cleared card detect\n"); if (!_sd_storage_get_scr(storage, buf)) return 0; - - //gfx_hexdump(0, storage->raw_scr, 8); DPRINTF("[SD] got scr\n"); - // Check if card supports a wider bus and if it's not SD Version 1.X - if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) + // If card supports a wider bus and if it's not SD Version 1.0 switch bus width. + if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & BIT(SD_BUS_WIDTH_4)) && storage->scr.sda_vsn) { if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) return 0; @@ -1310,6 +1351,7 @@ DPRINTF("[SD] switched to wide bus width\n"); } else { + bus_width = SDMMC_BUS_WIDTH_1; DPRINTF("[SD] SD does not support wide bus width\n"); } @@ -1321,7 +1363,7 @@ DPRINTF("[SD] enabled UHS\n"); sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); } - else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0) + else if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0. { if (!_sd_storage_enable_hs_high_volt(storage, buf)) return 0; @@ -1340,7 +1382,7 @@ DPRINTF("[SD] enabled HS\n"); } // Parse additional card info from sd status. - if (_sd_storage_get_ssr(storage, buf)) + if (sd_storage_get_ssr(storage, buf)) { DPRINTF("[SD] got sd status\n"); } @@ -1351,14 +1393,14 @@ DPRINTF("[SD] got sd status\n"); } /* -* Gamecard specific functions. -*/ + * Gamecard specific functions. + */ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) { u32 resp; sdmmc_cmd_t cmdbuf; - sdmmc_init_cmd(&cmdbuf, 60, 0, SDMMC_RSP_TYPE_1, 1); + sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_60_CMD, 0, SDMMC_RSP_TYPE_1, 1); sdmmc_req_t reqbuf; reqbuf.buf = buf; @@ -1366,9 +1408,9 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) reqbuf.num_sectors = 1; reqbuf.is_write = 1; reqbuf.is_multi_block = 0; - reqbuf.is_auto_cmd12 = 0; + reqbuf.is_auto_stop_trn = 0; - if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) { sdmmc_stop_transmission(storage->sdmmc, &resp); return 0; @@ -1376,7 +1418,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1)) return 0; - if (!_sdmmc_storage_check_result(resp)) + if (!_sdmmc_storage_check_card_status(resp)) return 0; return _sdmmc_storage_check_status(storage); } diff --git a/bdk/storage/sdmmc.h b/bdk/storage/sdmmc.h index 68d70f0..2b59f7d 100644 --- a/bdk/storage/sdmmc.h +++ b/bdk/storage/sdmmc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -30,18 +30,18 @@ typedef enum _sdmmc_type EMMC_GPP = 0, EMMC_BOOT0 = 1, - EMMC_BOOT1 = 2 + EMMC_BOOT1 = 2, + EMMC_RPMB = 3 } sdmmc_type; typedef struct _mmc_cid { u32 manfid; u8 prod_name[8]; - u8 card_bga; - u8 prv; u32 serial; u16 oemid; u16 year; + u8 prv; u8 hwrev; u8 fwrev; u8 month; @@ -65,19 +65,20 @@ typedef struct _mmc_csd typedef struct _mmc_ext_csd { - u32 sectors; - int bkops; /* background support bit */ - int bkops_en; /* manual bkops enable bit */ + //u8 bkops; /* background support bit */ + //u8 bkops_en; /* manual bkops enable bit */ + //u8 bkops_status; /* 246 */ u8 rev; u8 ext_struct; /* 194 */ u8 card_type; /* 196 */ - u8 bkops_status; /* 246 */ u8 pre_eol_info; u8 dev_life_est_a; u8 dev_life_est_b; u8 boot_mult; u8 rpmb_mult; u16 dev_version; + u32 cache_size; + u32 max_enh_mult; } mmc_ext_csd_t; typedef struct _sd_scr @@ -90,11 +91,13 @@ typedef struct _sd_scr typedef struct _sd_ssr { - u8 bus_width; - u8 speed_class; - u8 uhs_grade; - u8 video_class; - u8 app_class; + u8 bus_width; + u8 speed_class; + u8 uhs_grade; + u8 video_class; + u8 app_class; + u8 au_size; + u8 uhs_au_size; u32 protected_size; } sd_ssr_t; @@ -107,6 +110,7 @@ typedef struct _sdmmc_storage_t u32 sec_cnt; int is_low_voltage; u32 partition; + int initialized; u8 raw_cid[0x10]; u8 raw_csd[0x10]; u8 raw_scr[8]; @@ -116,16 +120,18 @@ typedef struct _sdmmc_storage_t mmc_ext_csd_t ext_csd; sd_scr_t scr; sd_ssr_t ssr; - int initialized; } sdmmc_storage_t; -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_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 bus_width, u32 type); -int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +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_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 bus_width, u32 type); +int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); void sdmmc_storage_init_wait_sd(); -int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); -int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); +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 sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf); +u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage); #endif diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c index 3eaded0..5ceb2e7 100644 --- a/bdk/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -501,7 +501,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) break; case SDMMC_RSP_TYPE_2: - if (size < 0x10) + if (size < 16) return 0; rsp[0] = sdmmc->rsp[0]; rsp[1] = sdmmc->rsp[1]; @@ -934,12 +934,20 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) *blkcnt_out = blkcnt; u32 trnmode = SDHCI_TRNS_DMA; + + // Set mulitblock request. if (req->is_multi_block) trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA; + + // Set request direction. if (!req->is_write) trnmode |= SDHCI_TRNS_READ; - if (req->is_auto_cmd12) - trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12; + + // Automatic send of stop transmission or set block count cmd. + if (req->is_auto_stop_trn) + trnmode |= SDHCI_TRNS_AUTO_CMD12; + //else if (req->is_auto_set_blkcnt) + // trnmode |= SDHCI_TRNS_AUTO_CMD23; sdmmc->regs->trnmod = trnmode; @@ -1052,7 +1060,7 @@ DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, if (!result) { #ifdef ERROR_EXTRA_PRINTING - EPRINTFARGS("SDMMC: DMA Update failed (%08X)!", result); + EPRINTF("SDMMC: DMA Update failed!"); #endif } } @@ -1070,7 +1078,7 @@ DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, if (blkcnt_out) *blkcnt_out = blkcnt; - if (req->is_auto_cmd12) + if (req->is_auto_stop_trn) sdmmc->rsp3 = sdmmc->regs->rspreg3; } @@ -1200,8 +1208,8 @@ static int _sdmmc_config_sdmmc1(bool t210b01) usleep(10000); // Enable SD card IO power. - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - max77620_regulator_enable(REGULATOR_LDO2, 1); + max7762x_regulator_set_voltage(REGULATOR_LDO2, 3300000); + max7762x_regulator_enable(REGULATOR_LDO2, true); usleep(1000); // Set pad slew codes to get good quality clock. @@ -1332,18 +1340,6 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int p void sdmmc1_disable_power() { - // Ensure regulator is into default voltage. - if (PMC(APBDEV_PMC_PWR_DET_VAL) & PMC_PWR_DET_SDMMC1_IO_EN) - { - // Switch to 1.8V and wait for regulator to stabilize. - max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); - usleep(150); - - // Inform IO pads that we switched to 1.8V. - PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN); - (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. - } - // T210B01 WAR: Clear pull down from CLK pad. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK; @@ -1351,7 +1347,7 @@ void sdmmc1_disable_power() _sdmmc_config_sdmmc1_pads(true); // Disable SD card IO power regulator. - max77620_regulator_enable(REGULATOR_LDO2, 0); + max7762x_regulator_enable(REGULATOR_LDO2, false); usleep(4000); // Disable SD card IO power pin. @@ -1383,12 +1379,12 @@ void sdmmc_end(sdmmc_t *sdmmc) _sdmmc_sd_clock_disable(sdmmc); // Disable SDMMC power. _sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF); + _sdmmc_commit_changes(sdmmc); // Disable SD card power. if (sdmmc->id == SDMMC_1) sdmmc1_disable_power(); - _sdmmc_commit_changes(sdmmc); clock_sdmmc_disable(sdmmc->id); sdmmc->clock_stopped = 1; } @@ -1440,7 +1436,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_commit_changes(sdmmc); // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. - max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); + max7762x_regulator_set_voltage(REGULATOR_LDO2, 1800000); usleep(150); // Inform IO pads that we switched to 1.8V. diff --git a/bdk/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h index fb2b1b3..696ce4d 100644 --- a/bdk/storage/sdmmc_driver.h +++ b/bdk/storage/sdmmc_driver.h @@ -242,7 +242,7 @@ typedef struct _sdmmc_req_t u32 num_sectors; int is_write; int is_multi_block; - int is_auto_cmd12; + int is_auto_stop_trn; } sdmmc_req_t; int sdmmc_get_io_power(sdmmc_t *sdmmc); diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c index f39b082..14379e3 100644 --- a/bdk/thermal/fan.c +++ b/bdk/thermal/fan.c @@ -26,7 +26,7 @@ void set_fan_duty(u32 duty) { static bool fan_init = false; - static u16 curr_duty = -1; + static u16 curr_duty = -1; if (curr_duty == duty) return; @@ -56,7 +56,7 @@ void set_fan_duty(u32 duty) if (inv_duty == 236) { PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Bit 24 is absolute 0%. - regulator_disable_5v(REGULATOR_5V_FAN); + regulator_5v_disable(REGULATOR_5V_FAN); // Disable fan. PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = @@ -65,7 +65,7 @@ void set_fan_duty(u32 duty) else // Set PWM duty. { // Fan power supply. - regulator_enable_5v(REGULATOR_5V_FAN); + regulator_5v_enable(REGULATOR_5V_FAN); PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16); // Enable fan. @@ -79,15 +79,14 @@ void get_fan_speed(u32 *duty, u32 *rpm) { if (rpm) { - u32 irq_count = 1; + u32 irq_count = 0; bool should_read = true; - bool irq_val = 0; - // Poll irqs for 2 seconds. - int timer = get_tmr_us() + 1000000; - while (timer - get_tmr_us()) + // Poll irqs for 2 seconds. (5 seconds for accurate count). + int timer = get_tmr_us() + 2000000; + while ((timer - get_tmr_us()) > 0) { - irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); + bool irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); if (irq_val && should_read) { irq_count++; @@ -97,8 +96,11 @@ void get_fan_speed(u32 *duty, u32 *rpm) should_read = true; } + // Halve the irq count. + irq_count /= 2; + // Calculate rpm based on triggered interrupts. - *rpm = 60000000 / ((1000000 * 2) / irq_count); + *rpm = irq_count * (60 / 2); } if (duty) diff --git a/bdk/thermal/tmp451.c b/bdk/thermal/tmp451.c index fb9f9fa..65f2fd2 100644 --- a/bdk/thermal/tmp451.c +++ b/bdk/thermal/tmp451.c @@ -1,7 +1,7 @@ /* * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-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, @@ -16,7 +16,9 @@ * along with this program. If not, see . */ +#include #include +#include #include u16 tmp451_get_soc_temp(bool intenger) @@ -56,6 +58,20 @@ void tmp451_init() // Disable ALARM and Range to 0 - 127 oC. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0x80); + // Set remote sensor offsets based on SoC. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + // Set offset to 0 oC for Erista. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0); + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0); + } + else + { + // Set offset to -12.5 oC for Mariko. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0xF3); // - 13 oC. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0x80); // + 0.5 oC. + } + // Set conversion rate to 32/s and make a read to update the reg. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 9); tmp451_get_soc_temp(false); @@ -63,3 +79,9 @@ void tmp451_init() // Set rate to every 4 seconds. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 2); } + +void tmp451_end() +{ + // Place into shutdown mode to conserve power. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0xC0); +} diff --git a/bdk/thermal/tmp451.h b/bdk/thermal/tmp451.h index 9549ffa..6258fbd 100644 --- a/bdk/thermal/tmp451.h +++ b/bdk/thermal/tmp451.h @@ -32,11 +32,15 @@ #define TMP451_SOC_TMP_DEC_REG 0x10 #define TMP451_PCB_TMP_DEC_REG 0x15 +#define TMP451_SOC_TMP_OFH_REG 0x11 +#define TMP451_SOC_TMP_OFL_REG 0x12 + // If input is false, the return value is packed. MSByte is the integer in oC // and the LSByte is the decimal point truncated to 2 decimal places. // Otherwise it's an integer oC. u16 tmp451_get_soc_temp(bool integer); u16 tmp451_get_pcb_temp(bool integer); void tmp451_init(); +void tmp451_end(); #endif /* __TMP451_H_ */ diff --git a/bdk/usb/usb_gadget_hid.c b/bdk/usb/usb_gadget_hid.c index 3437b40..b7c2e24 100644 --- a/bdk/usb/usb_gadget_hid.c +++ b/bdk/usb/usb_gadget_hid.c @@ -309,7 +309,7 @@ static bool _fts_touch_read(touchpad_report_t *rpt) static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len) { - u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED); + u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED_CMD); if (status == USB_ERROR_XFER_ERROR) { usbs->set_text(usbs->label, "#FFDD00 Error:# EP IN transfer!"); diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c index 97deeb5..10bd56a 100644 --- a/bdk/usb/usb_gadget_ums.c +++ b/bdk/usb/usb_gadget_ums.c @@ -58,7 +58,7 @@ #define UMS_SCSI_TRANSFER_512K (0x80000 >> UMS_DISK_LBA_SHIFT) -#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER >> UMS_DISK_LBA_SHIFT) +#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER) // Length of a SCSI Command Data Block. #define SCSI_MAX_CMD_SZ 16 @@ -121,6 +121,15 @@ enum ums_state { UMS_STATE_TERMINATED }; +enum ums_result { + UMS_RES_OK = 0, + UMS_RES_IO_ERROR = -5, + UMS_RES_TIMEOUT = -3, + UMS_RES_PROT_FATAL = -4, + UMS_RES_INVALID_ARG = -22 +}; + + enum data_direction { DATA_DIR_UNKNOWN = 0, DATA_DIR_FROM_HOST, @@ -194,7 +203,7 @@ typedef struct _bulk_ctxt_t { typedef struct _usbd_gadget_ums_t { bulk_ctxt_t bulk_ctxt; - int cmnd_size; + u32 cmnd_size; u8 cmnd[SCSI_MAX_CMD_SZ]; u32 lun_idx; // lun index @@ -283,21 +292,21 @@ static int ums_wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums) { /* usbd_set_ep_wedge(bulk_ctxt->bulk_in); */ - return 0; + return UMS_RES_OK; } static int ums_set_stall(u32 ep) { usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_STALL); - return 0; + return UMS_RES_OK; } static int ums_clear_stall(u32 ep) { usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_CLEAR); - return 0; + return UMS_RES_OK; } static void ums_flush_endpoint(u32 ep) @@ -306,13 +315,13 @@ static void ums_flush_endpoint(u32 ep) usb_ops.usbd_flush_endpoint(ep); } -static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync) +static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout) { if (ep == bulk_ctxt->bulk_in) { bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_write( bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, - &bulk_ctxt->bulk_in_length_actual, sync); + &bulk_ctxt->bulk_in_length_actual, sync_timeout); if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) { @@ -322,14 +331,14 @@ static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, else if (bulk_ctxt->bulk_in_status == USB2_ERROR_XFER_NOT_ALIGNED) ums->set_text(ums->label, "#FFDD00 Error:# EP IN Buffer not aligned!"); - if (sync) + if (sync_timeout) bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; } else { bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read( bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, - &bulk_ctxt->bulk_out_length_actual, sync); + &bulk_ctxt->bulk_out_length_actual, sync_timeout); if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { @@ -339,7 +348,7 @@ static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, else if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_NOT_ALIGNED) ums->set_text(ums->label, "#FFDD00 Error:# EP OUT Buffer not aligned!"); - if (sync) + if (sync_timeout) bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; } } @@ -377,7 +386,7 @@ static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, else { bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish( - &bulk_ctxt->bulk_out_length_actual, 1000000); + &bulk_ctxt->bulk_out_length_actual); if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { @@ -446,20 +455,20 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } } if (lba_offset >= ums->lun.num_sectors) { ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } // Check that request data size is not 0. u32 amount_left = ums->data_size_from_cmnd >> UMS_DISK_LBA_SHIFT; if (!amount_left) - return -5; // I/O error. /* No default reply */ + return UMS_RES_IO_ERROR; // No default reply. // Limit IO transfers based on request for faster concurrent reads. u32 max_io_transfer = (amount_left >= UMS_SCSI_TRANSFER_512K) ? @@ -520,7 +529,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) sdmmc_buf += amount << UMS_DISK_LBA_SHIFT; } - return -5; // I/O error no default reply here. /* No default reply */ + return UMS_RES_IO_ERROR; // No default reply. } /* @@ -541,7 +550,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_WRITE_PROTECTED; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } if (ums->cmnd[0] == SC_WRITE_6) @@ -555,7 +564,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } } @@ -564,7 +573,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Carry out the file writes */ @@ -574,22 +583,20 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) while (amount_left_to_write > 0) { - /* Queue a request for more data from the host */ - if (amount_left_to_req) + if (amount_left_to_req > 0) { // Limit write to max supported read from EP OUT. - amount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER << UMS_DISK_LBA_SHIFT); + amount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER); - if (usb_lba_offset >= ums->lun.num_sectors) //////////Check if it works with concurrency + if (usb_lba_offset >= ums->lun.num_sectors) { ums->set_text(ums->label, "#FFDD00 Error:# Write - Past last sector!"); - amount_left_to_req = 0; ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ums->lun.sense_data_info = usb_lba_offset; ums->lun.info_valid = 1; - continue; + break; } // Get the next buffer. @@ -612,7 +619,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) ums->lun.sense_data = SS_COMMUNICATION_FAILURE; ums->lun.sense_data_info = lba_offset; ums->lun.info_valid = 1; - sprintf(txt_buf, "#FFDD00 Error:# Write - Comm failure %d!", bulk_ctxt->bulk_out_status); + s_printf(txt_buf, "#FFDD00 Error:# Write - Comm failure %d!", bulk_ctxt->bulk_out_status); ums->set_text(ums->label, txt_buf); break; } @@ -668,7 +675,7 @@ DPRINTF("file write %X @ %X\n", amount, lba_offset); } } - return -5; // I/O error. /* No default reply */ + return UMS_RES_IO_ERROR; // No default reply. } static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -679,7 +686,7 @@ static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } // We allow DPO but we don't implement it. Check that nothing else is enabled. @@ -687,12 +694,12 @@ static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } u32 verification_length = get_array_be_to_le16(&ums->cmnd[7]); if (verification_length == 0) - return -5; // I/O error. /* No default reply */ + return UMS_RES_IO_ERROR; // No default reply. u32 amount; while (verification_length > 0) @@ -724,7 +731,7 @@ DPRINTF("File read %X @ %X\n", amount, lba_offset); lba_offset += amount; verification_length -= amount; } - return 0; + return UMS_RES_OK; } static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -742,7 +749,7 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) buf[3] = 20; // Additional length. buf += 4; - sprintf((char *)buf, "%04X%s", + s_printf((char *)buf, "%04X%s", ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC "); switch (ums->lun.partition) @@ -751,13 +758,13 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) strcpy((char *)buf + strlen((char *)buf), "RAW"); break; case EMMC_GPP + 1: - sprintf((char *)buf + strlen((char *)buf), "GPP"); + s_printf((char *)buf + strlen((char *)buf), "GPP"); break; case EMMC_BOOT0 + 1: - sprintf((char *)buf + strlen((char *)buf), "BOOT0"); + s_printf((char *)buf + strlen((char *)buf), "BOOT0"); break; case EMMC_BOOT1 + 1: - sprintf((char *)buf + strlen((char *)buf), "BOOT1"); + s_printf((char *)buf + strlen((char *)buf), "BOOT1"); break; } @@ -784,18 +791,18 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) switch (ums->lun.partition) { case 0: - sprintf((char *)buf, "%s", "SD RAW"); + s_printf((char *)buf, "%s", "SD RAW"); break; case EMMC_GPP + 1: - sprintf((char *)buf, "%s%s", + s_printf((char *)buf, "%s%s", ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP"); break; case EMMC_BOOT0 + 1: - sprintf((char *)buf, "%s%s", + s_printf((char *)buf, "%s%s", ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0"); break; case EMMC_BOOT1 + 1: - sprintf((char *)buf, "%s%s", + s_printf((char *)buf, "%s%s", ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1"); break; } @@ -843,7 +850,7 @@ static int _scsi_read_capacity(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } put_array_le_to_be32(ums->lun.num_sectors - 1, &buf[0]); // Max logical block. @@ -866,14 +873,14 @@ static int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } if (pc != 1) // Current cumulative values. { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } memset(buf, 0, 8); @@ -915,7 +922,7 @@ static int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } put_array_le_to_be16(len - 4, &buf0[2]); @@ -938,14 +945,14 @@ static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } if (pc == 3) { ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Write the mode parameter header. Fixed values are: default @@ -995,7 +1002,7 @@ static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Store the mode data length */ @@ -1015,14 +1022,14 @@ static int _scsi_start_stop(usbd_gadget_ums_t *ums) { ums->lun.sense_data = SS_INVALID_COMMAND; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } else if ((ums->cmnd[1] & ~0x01) != 0 || // Mask away Immed. (ums->cmnd[4] & ~0x03) != 0) // Mask LoEj, Start. { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; + return UMS_RES_INVALID_ARG; } loej = ums->cmnd[4] & 0x02; @@ -1035,10 +1042,10 @@ static int _scsi_start_stop(usbd_gadget_ums_t *ums) { ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; - return -22; + return UMS_RES_INVALID_ARG; } - return 0; + return UMS_RES_OK; } // Check if we are allowed to unload the media. @@ -1047,16 +1054,16 @@ static int _scsi_start_stop(usbd_gadget_ums_t *ums) ums->set_text(ums->label, "#C7EA46 Status:# Unload attempt prevented"); ums->lun.sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -22; + return UMS_RES_INVALID_ARG; } if (!loej) - return 0; + return UMS_RES_OK; // Unmount means we exit UMS because of ejection. ums->lun.unmounted = 1; - return 0; + return UMS_RES_OK; } static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) @@ -1067,7 +1074,7 @@ static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) { ums->lun.sense_data = SS_INVALID_COMMAND; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } prevent = ums->cmnd[4] & 0x01; @@ -1075,7 +1082,7 @@ static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } // Notify for possible unmounting? @@ -1085,7 +1092,7 @@ static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) ums->lun.prevent_medium_removal = prevent; - return 0; + return UMS_RES_OK; } static int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -1105,7 +1112,7 @@ static int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bul // Check whether the command is properly formed and whether its data size // and direction agree with the values we already have. -static int _ums_check_scsi_cmd(usbd_gadget_ums_t *ums, int cmnd_size, +static int _ums_check_scsi_cmd(usbd_gadget_ums_t *ums, u32 cmnd_size, enum data_direction data_dir, u32 mask, int needs_medium) { //const char dirletter[4] = {'u', 'o', 'i', 'n'}; @@ -1132,7 +1139,7 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", { ums->phase_error = 1; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } // Cmd length verification. @@ -1146,7 +1153,7 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", { ums->phase_error = 1; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } } @@ -1167,7 +1174,7 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", ums->lun.sense_data = ums->lun.unit_attention_data; ums->lun.unit_attention_data = SS_NO_SENSE; - return -22; + return UMS_RES_INVALID_ARG; } // Check that only command bytes listed in the mask are set. @@ -1178,7 +1185,7 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", { ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } } @@ -1187,16 +1194,16 @@ DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", { ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; - return -22; + return UMS_RES_INVALID_ARG; } - return 0; + return UMS_RES_OK; } static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { u32 len; - int reply = -22; // Invalid argument. + int reply = UMS_RES_INVALID_ARG; ums->phase_error = 0; ums->short_packet_received = 0; @@ -1227,7 +1234,7 @@ static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { // We don't support MODE SELECT. ums->lun.sense_data = SS_INVALID_COMMAND; - reply = -22; + reply = UMS_RES_INVALID_ARG; } break; @@ -1238,7 +1245,7 @@ static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { // We don't support MODE SELECT. ums->lun.sense_data = SS_INVALID_COMMAND; - reply = -22; + reply = UMS_RES_INVALID_ARG; } break; @@ -1367,12 +1374,12 @@ static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (reply == 0) { ums->lun.sense_data = SS_INVALID_COMMAND; - reply = -22; // Invalid argument. + reply = UMS_RES_INVALID_ARG; } break; } - if (reply == -22) // Invalid argument. + if (reply == UMS_RES_INVALID_ARG) reply = 0; // Error reply length. // Set up reply buffer for finish_reply(). Otherwise it's already set. @@ -1384,7 +1391,7 @@ static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) ums->residue -= reply; } - return 0; + return UMS_RES_OK; } static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -1398,12 +1405,12 @@ static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); bulk_ctxt->bulk_in_length = nsend; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); ums->usb_amount_left -= nsend; current_len_to_keep = 0; } - return 0; + return UMS_RES_OK; } static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -1416,10 +1423,10 @@ static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); bulk_ctxt->bulk_out_length = amount; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_DATA); ums->usb_amount_left -= amount; - return 0; + return UMS_RES_OK; } // Throw away the data in a filled buffer. @@ -1431,15 +1438,15 @@ static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) bulk_ctxt->bulk_out_status != USB_RES_OK) { raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); - return -4; // Interrupted system call + return UMS_RES_PROT_FATAL; } } - return 0; + return UMS_RES_OK; } static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { - int rc = 0; + int rc = UMS_RES_OK; switch (ums->data_dir) { case DATA_DIR_NONE: @@ -1463,7 +1470,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // If there's no residue, simply send the last buffer. if (!ums->residue) { - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); /* For Bulk-only, if we're allowed to stall then send the * short packet and halt the bulk-in endpoint. If we can't @@ -1471,7 +1478,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) } else if (ums->can_stall) { - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); rc = ums_set_stall(bulk_ctxt->bulk_in); ums->set_text(ums->label, "#FFDD00 Error:# Residue. Stalled EP IN!"); } @@ -1491,7 +1498,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (ums->short_packet_received) // Did the host stop sending unexpectedly early? { raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); - rc = -4; // Interrupted system call + rc = UMS_RES_PROT_FATAL; } else // We can't stall. Read in the excess data and throw it away. rc = throw_away_data(ums, bulk_ctxt); @@ -1574,7 +1581,7 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) } if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore) - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Is the CBW valid? */ @@ -1594,12 +1601,12 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // until the next reset. ums_wedge_bulk_in_endpoint(ums); bulk_ctxt->bulk_out_ignore = 1; - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Is the CBW meaningful? */ if (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length <= 0 || cbw->Length > SCSI_MAX_CMD_SZ) + cbw->Length == 0 || cbw->Length > SCSI_MAX_CMD_SZ) { gfx_printf("USB: non-meaningful CBW: lun = %X, flags = 0x%X, cmdlen %X\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -1613,7 +1620,7 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) ums->set_text(ums->label, "#FFDD00 Error:# CBW unknown - Stalled both EP!"); } - return -22; // Invalid argument. + return UMS_RES_INVALID_ARG; } /* Save the command for later */ @@ -1636,12 +1643,12 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (!ums->lun.unmounted) ums->timeouts = 0; - return 0; + return UMS_RES_OK; } static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { - int rc = 0; + int rc = UMS_RES_OK; /* Wait for the next buffer to become available */ // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY) @@ -1652,7 +1659,7 @@ static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; /* Queue a request to read a Bulk-only CBW */ - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); /* We will drain the buffer in software, which means we * can reuse it for the next filling. No need to advance @@ -1698,7 +1705,7 @@ static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) csw->Status = status; bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_CMD); } static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) @@ -1765,16 +1772,16 @@ static inline void _system_maintainance(usbd_gadget_ums_t *ums) u32 time = get_tmr_ms(); - if (timer_dram < time) - { - minerva_periodic_training(); - timer_dram = get_tmr_ms() + 100; - } - else if (timer_status_bar < time) + if (timer_status_bar < time) { ums->system_maintenance(true); timer_status_bar = get_tmr_ms() + 30000; } + else if (timer_dram < time) + { + minerva_periodic_training(); + timer_dram = get_tmr_ms() + EMC_PERIODIC_TRAIN_MS; + } } int usb_device_gadget_ums(usb_ctxt_t *usbs) @@ -1828,6 +1835,7 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs) // Initialize sdmmc. if (usbs->type == MMC_SD) { + sd_end(); sd_mount(); sd_unmount(); ums.lun.sdmmc = &sd_sdmmc; @@ -1898,7 +1906,10 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs) send_status(&ums, &ums.bulk_ctxt); } while (ums.state != UMS_STATE_TERMINATED); - ums.set_text(ums.label, "#C7EA46 Status:# Disk ejected"); + if (ums.lun.prevent_medium_removal) + ums.set_text(ums.label, "#FFDD00 Error:# Disk unsafely ejected"); + else + ums.set_text(ums.label, "#C7EA46 Status:# Disk ejected"); goto exit; error: diff --git a/bdk/usb/usb_t210.h b/bdk/usb/usb_t210.h index 4d67c69..e677a5f 100644 --- a/bdk/usb/usb_t210.h +++ b/bdk/usb/usb_t210.h @@ -198,6 +198,7 @@ typedef struct _t210_usb2d_t #define XUSB_DEV_XHCI_ST 0x34 #define XHCI_ST_RC BIT(0) #define XHCI_ST_IP BIT(4) +#define XUSB_DEV_XHCI_RT_IMOD 0x38 #define XUSB_DEV_XHCI_PORTSC 0x3C #define XHCI_PORTSC_PR BIT(4) #define XHCI_PORTSC_PLS_MASK (0xF << 5) diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c index 8cf37c3..95d1ed5 100644 --- a/bdk/usb/usbd.c +++ b/bdk/usb/usbd.c @@ -724,7 +724,7 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) return USB_EP_STATUS_IDLE; } -static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) +static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, u32 sync_timeout) { if (!buf) len = 0; @@ -797,12 +797,12 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) int res = USB_RES_OK; usb_ep_status_t ep_status; - if (sync) + if (sync_timeout) { ep_status = _usbd_get_ep_status(endpoint); if (ep_status == USB_EP_STATUS_ACTIVE) { - u32 retries = 1000000; // Timeout 2s. + u32 retries = sync_timeout; while (retries) { ep_status = _usbd_get_ep_status(endpoint); @@ -834,7 +834,7 @@ out: static int _usbd_ep_ack(usb_ep_t ep) { - return _usbd_ep_operation(ep, NULL, 0, true); + return _usbd_ep_operation(ep, NULL, 0, USB_XFER_SYNCED_ENUM); } static void _usbd_set_ep0_stall() @@ -1275,7 +1275,7 @@ static int _usbd_handle_ep0_control_transfer() if (_wLength < size) size = _wLength; - res = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, true); + res = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, USB_XFER_SYNCED_ENUM); if (!res) res = _usbd_ep_ack(USB_EP_CTRL_OUT); } @@ -1402,7 +1402,7 @@ static usb_ep_status_t _usbd_get_ep1_status(usb_dir_t dir) return _usbd_get_ep_status(ep); } -int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) +int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_timeout) { if ((u32)buf % USB_EP_BUFFER_ALIGN) return USB2_ERROR_XFER_NOT_ALIGNED; @@ -1410,9 +1410,9 @@ int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; - int res = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync); + int res = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync_timeout); - if (sync && bytes_read) + if (sync_timeout && bytes_read) *bytes_read = res ? 0 : len; return res; @@ -1435,7 +1435,7 @@ int usb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) { u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); - res = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED); + res = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA); if (res) return res; @@ -1455,7 +1455,7 @@ static int _usbd_get_ep1_out_bytes_read() return (usbdaemon->ep_bytes_requested[USB_EP_BULK_OUT] - (usbdaemon->qhs[USB_EP_BULK_OUT].token >> 16)); } -int usb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) +int usb_device_ep1_out_reading_finish(u32 *pending_bytes) { usb_ep_status_t ep_status; do @@ -1480,7 +1480,7 @@ int usb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) return USB_ERROR_XFER_ERROR; } -int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) +int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_timeout) { if ((u32)buf % USB_EP_BUFFER_ALIGN) return USB2_ERROR_XFER_NOT_ALIGNED; @@ -1488,9 +1488,9 @@ int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; - int res = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync); + int res = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync_timeout); - if (sync && bytes_written) + if (sync_timeout && bytes_written) *bytes_written = res ? 0 : len; return res; diff --git a/bdk/usb/usbd.h b/bdk/usb/usbd.h index 6ba2a5a..a0e4a63 100644 --- a/bdk/usb/usbd.h +++ b/bdk/usb/usbd.h @@ -30,8 +30,12 @@ #define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) #define USB_EP_BUFFER_ALIGN (USB_TD_BUFFER_PAGE_SIZE) -#define USB_XFER_START false -#define USB_XFER_SYNCED true +#define USB_XFER_START 0 +#define USB_XFER_SYNCED_ENUM 1000000 +#define USB_XFER_SYNCED_CMD 1000000 +#define USB_XFER_SYNCED_DATA 2000000 +#define USB_XFER_SYNCED_CLASS 5000000 +#define USB_XFER_SYNCED -1 typedef enum _usb_hid_type { @@ -169,10 +173,10 @@ typedef struct _usb_ops_t int (*usb_device_class_send_max_lun)(u8); int (*usb_device_class_send_hid_report)(); - int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, bool); + int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32); int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *); - int (*usb_device_ep1_out_reading_finish)(u32 *, int); - int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, bool); + int (*usb_device_ep1_out_reading_finish)(u32 *); + int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, u32); int (*usb_device_ep1_in_writing_finish)(u32 *); bool (*usb_device_get_suspended)(); bool (*usb_device_get_port_in_sleep)(); diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c index e33ca44..4beefcd 100644 --- a/bdk/usb/xusbd.c +++ b/bdk/usb/xusbd.c @@ -881,7 +881,7 @@ int xusb_device_init() _xusbd_init_device_clocks(); // Enable AHB redirect for access to IRAM for Event/EP ring buffers. - mc_enable_ahb_redirect(); // can be skipped if IRAM is not used///////////////// + mc_enable_ahb_redirect(); // Can be skipped if IRAM is not used. // Enable XUSB device IPFS. XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI; @@ -895,14 +895,11 @@ int xusb_device_init() XUSB_DEV_DEV(XUSB_DEV_INTR_MASK) |= DEV_INTR_MASK_IP_INT_MASK; // AHB USB performance cfg. - //TODO: Doesn't help.. -/* AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE; AHB_GIZMO(AHB_GIZMO_USB3) |= AHB_GIZMO_IMMEDIATE; AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB3; AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = MEM_PREFETCH_ENABLE | MEM_PREFETCH_USB3_MST_ID | MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles. -*/ // Initialize context. usbd_xotg = &usbd_xotg_controller_ctxt; @@ -1771,6 +1768,13 @@ int xusb_device_enumerate(usb_gadget_type gadget) usbd_xotg->gadget = gadget; + /* + * Set interrupt moderation to 0us. + * This is important because default value creates a 4.62ms latency. + * Effectively hurting transfers by having 15% to 96% performance loss. + */ + XUSB_DEV_XHCI(XUSB_DEV_XHCI_RT_IMOD) = 0; + // Disable Wake events. XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_0) = 0; XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_1) = 0; @@ -1803,7 +1807,7 @@ int xusb_device_enumerate(usb_gadget_type gadget) u32 timer = get_tmr_ms() + 90000; while (true) { - int res = _xusb_ep_operation(1000000); // 2s timeout. + int res = _xusb_ep_operation(USB_XFER_SYNCED_ENUM); // 2s timeout. if (res && res != USB_ERROR_TIMEOUT) return res; @@ -1826,7 +1830,7 @@ void xusb_end(bool reset_ep, bool only_controller) CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB); CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); - mc_disable_ahb_redirect();/////////////////// + mc_disable_ahb_redirect(); // Can be skipped if IRAM is not used. } int xusb_handle_ep0_ctrl_setup() @@ -1844,7 +1848,7 @@ int xusb_handle_ep0_ctrl_setup() return USB_RES_OK; } -int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) +int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries) { if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; @@ -1855,10 +1859,10 @@ int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync) _xusb_issue_normal_trb(buf, len, USB_DIR_OUT); usbd_xotg->tx_count[USB_DIR_OUT]++; - if (sync) + if (sync_tries) { while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) - res = _xusb_ep_operation(1000000); // 2s timeout. + res = _xusb_ep_operation(sync_tries); if (bytes_read) *bytes_read = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; @@ -1882,7 +1886,7 @@ int xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) { u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); - int res = xusb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED); + int res = xusb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA); if (res) return res; @@ -1894,11 +1898,11 @@ int xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) return USB_RES_OK; } -int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) +int xusb_device_ep1_out_reading_finish(u32 *pending_bytes) { int res = USB_RES_OK; while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) - res = _xusb_ep_operation(tries); + res = _xusb_ep_operation(USB_XFER_SYNCED); // Infinite retries. if (pending_bytes) *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; @@ -1908,7 +1912,7 @@ int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries) return res; } -int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) +int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_tries) { if (len > USB_EP_BUFFER_MAX_SIZE) len = USB_EP_BUFFER_MAX_SIZE; @@ -1921,10 +1925,10 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync) _xusb_issue_normal_trb(buf, len, USB_DIR_IN); usbd_xotg->tx_count[USB_DIR_IN]++; - if (sync) + if (sync_tries) { while (!res && usbd_xotg->tx_count[USB_DIR_IN]) - res = _xusb_ep_operation(1000000); // 2s timeout. + res = _xusb_ep_operation(sync_tries); if (bytes_written) *bytes_written = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; @@ -1947,7 +1951,7 @@ int xusb_device_ep1_in_writing_finish(u32 *pending_bytes) { int res = USB_RES_OK; while (!res && usbd_xotg->tx_count[USB_DIR_IN]) - res = _xusb_ep_operation(1000000); // 2s timeout. + res = _xusb_ep_operation(USB_XFER_SYNCED); // Infinite retries. if (pending_bytes) *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; @@ -1973,7 +1977,7 @@ bool xusb_device_class_send_max_lun(u8 max_lun) // Wait for request and transfer start. while (usbd_xotg->device_state != XUSB_LUN_CONFIGURED) { - _xusb_ep_operation(500000); + _xusb_ep_operation(USB_XFER_SYNCED_CLASS); if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) return true; } @@ -1991,7 +1995,7 @@ bool xusb_device_class_send_hid_report() // Wait for request and transfer start. while (usbd_xotg->device_state != XUSB_HID_CONFIGURED) { - _xusb_ep_operation(500000); + _xusb_ep_operation(USB_XFER_SYNCED_CLASS); if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) return true; } diff --git a/bdk/utils/btn.c b/bdk/utils/btn.c index 9ffe275..cc36573 100644 --- a/bdk/utils/btn.c +++ b/bdk/utils/btn.c @@ -29,7 +29,7 @@ u8 btn_read() res |= BTN_VOL_DOWN; if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) res |= BTN_VOL_UP; - if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) + if (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & MAX77620_ONOFFSTAT_EN0) res |= BTN_POWER; return res; } diff --git a/bdk/utils/dirlist.c b/bdk/utils/dirlist.c index 5732683..3b09d1d 100644 --- a/bdk/utils/dirlist.c +++ b/bdk/utils/dirlist.c @@ -21,16 +21,16 @@ #include #include +#define MAX_ENTRIES 64 + char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs) { - u8 max_entries = 61; - int res = 0; u32 i = 0, j = 0, k = 0; DIR dir; FILINFO fno; - char *dir_entries = (char *)calloc(max_entries, 256); + char *dir_entries = (char *)calloc(MAX_ENTRIES, 256); char *temp = (char *)calloc(1, 256); if (!pattern && !f_opendir(&dir, directory)) @@ -49,7 +49,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { strcpy(dir_entries + (k * 256), fno.fname); k++; - if (k > (max_entries - 1)) + if (k > (MAX_ENTRIES - 1)) break; } } @@ -64,7 +64,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { strcpy(dir_entries + (k * 256), fno.fname); k++; - if (k > (max_entries - 1)) + if (k > (MAX_ENTRIES - 1)) break; } res = f_findnext(&dir, &fno); diff --git a/bdk/utils/ini.c b/bdk/utils/ini.c index 538435e..5088f51 100644 --- a/bdk/utils/ini.c +++ b/bdk/utils/ini.c @@ -66,14 +66,14 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type int ini_parse(link_t *dst, char *ini_path, bool is_dir) { + FIL fp; u32 lblen; u32 pathlen = strlen(ini_path); u32 k = 0; - char lbuf[512]; - char *filelist = NULL; - FIL fp; ini_sec_t *csec = NULL; + char *lbuf = NULL; + char *filelist = NULL; char *filename = (char *)malloc(256); strcpy(filename, ini_path); @@ -114,6 +114,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) return 0; } + lbuf = malloc(512); + do { // Fetch one line. @@ -168,6 +170,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) } } while (is_dir); + free(lbuf); free(filename); free(filelist); diff --git a/bdk/utils/sprintf.c b/bdk/utils/sprintf.c index c27043c..8fa2dec 100644 --- a/bdk/utils/sprintf.c +++ b/bdk/utils/sprintf.c @@ -56,7 +56,7 @@ static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) { return _puts(buffer, p); } -u32 sprintf(char *buffer, const char *fmt, ...) { +u32 s_printf(char *buffer, const char *fmt, ...) { va_list ap; int fill, fcnt; u32 count = 0; diff --git a/bdk/utils/sprintf.h b/bdk/utils/sprintf.h index 6094044..35a8218 100644 --- a/bdk/utils/sprintf.h +++ b/bdk/utils/sprintf.h @@ -19,6 +19,6 @@ #include "types.h" -u32 sprintf(char *buffer, const char *fmt, ...); +u32 s_printf(char *buffer, const char *fmt, ...); #endif diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 0300425..9e8e716 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -22,7 +22,7 @@ #define ALWAYS_INLINE inline __attribute__((always_inline)) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1)) #define BIT(n) (1U << (n)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -74,6 +74,9 @@ typedef int bool; #define true 1 #define false 0 +#define DISABLE 0 +#define ENABLE 1 + #define BOOT_CFG_AUTOBOOT_EN BIT(0) #define BOOT_CFG_FROM_LAUNCH BIT(1) #define BOOT_CFG_FROM_ID BIT(2) diff --git a/bdk/utils/util.c b/bdk/utils/util.c index e5cd868..f267236 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer +* Copyright (c) 2018-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, @@ -44,7 +44,7 @@ u32 get_tmr_ms() u32 get_tmr_us() { - return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US + return TMR(TIMERUS_CNTR_1US); } void msleep(u32 ms) @@ -132,53 +132,58 @@ void panic(u32 val) usleep(1); } -void reboot_normal() +void power_set_state(power_state_t state) { + u8 reg; + + // Unmount and power down sd card. sd_end(); - hw_reinit_workaround(false, 0); - panic(0x21); // Bypass fuse programming in package1. -} - -void reboot_rcm() -{ - sd_end(); - hw_reinit_workaround(false, 0); - - PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; - PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; - - while (true) - bpmp_halt(); -} - -void reboot_full() -{ - sd_end(); - hw_reinit_workaround(false, 0); - - // Enable soft reset wake event. - u8 reg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2); - reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK; - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg); - - // Do a soft reset. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST); - - while (true) - bpmp_halt(); -} - -void power_off() -{ - sd_end(); + // De-initialize and power down various hardware. hw_reinit_workaround(false, 0); // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + // Set power state. + switch (state) + { + case REBOOT_RCM: + PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; // Enable RCM path. + PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; // PMC reset. + break; + + case REBOOT_BYPASS_FUSES: + panic(0x21); // Bypass fuse programming in package1. + break; + + case POWER_OFF: + // Initiate power down sequence and do not generate a reset (regulators retain state). + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + break; + + case POWER_OFF_RESET: + case POWER_OFF_REBOOT: + default: + // Enable/Disable soft reset wake event. + reg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2); + if (state == POWER_OFF_RESET) // Do not wake up after power off. + reg &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK | MAX77620_ONOFFCNFG2_WK_ALARM1 | MAX77620_ONOFFCNFG2_WK_ALARM2); + else // POWER_OFF_REBOOT. Wake up after power off. + reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK; + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg); + + // Initiate power down sequence and generate a reset (regulators' state resets). + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST); + break; + } while (true) bpmp_halt(); } + +void power_set_state_ex(void *param) +{ + power_state_t *state = (power_state_t *)param; + power_set_state(*state); +} diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 20df76f..3503e1e 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -21,6 +21,16 @@ #include #include +typedef enum +{ + REBOOT_RCM, // PMC reset. Enter RCM mode. + REBOOT_BYPASS_FUSES, // PMC reset via watchdog. Enter Normal mode. Bypass fuse programming in package1. + + POWER_OFF, // Power off PMIC. Do not reset regulators. + POWER_OFF_RESET, // Power off PMIC. Reset regulators. + POWER_OFF_REBOOT, // Power off PMIC. Reset regulators. Power on. +} power_state_t; + typedef enum { NYX_CFG_BIS = BIT(5), @@ -41,6 +51,8 @@ typedef enum #define byte_swap_32(num) ((((num) >> 24) & 0xff) | (((num) << 8) & 0xff0000) | \ (((num) >> 8 )& 0xff00) | (((num) << 24) & 0xff000000)) +#define byte_swap_16(num) ((((num) >> 8) & 0xff) | (((num) << 8) & 0xff00)) + typedef struct _cfg_op_t { u32 off; @@ -49,6 +61,10 @@ typedef struct _cfg_op_t typedef struct _nyx_info_t { + u32 magic; + u32 sd_init; + u32 sd_errors[3]; + u8 rsvd[0x1000]; u32 disp_id; u32 errors; } nyx_info_t; @@ -65,17 +81,18 @@ typedef struct _nyx_storage_t emc_table_t mtc_table[10]; } nyx_storage_t; +void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); +u32 crc32_calc(u32 crc, const u8 *buf, u32 len); + u32 get_tmr_us(); u32 get_tmr_ms(); u32 get_tmr_s(); void usleep(u32 us); void msleep(u32 ms); + void panic(u32 val); -void reboot_normal(); -void reboot_rcm(); -void reboot_full(); -void power_off(); -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); -u32 crc32_calc(u32 crc, const u8 *buf, u32 len); +void power_set_state(power_state_t state); +void power_set_state_ex(void *param); + #endif diff --git a/source/config.c b/source/config.c index 254095e..55bd64e 100644 --- a/source/config.c +++ b/source/config.c @@ -49,6 +49,7 @@ void set_default_configuration() h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; h_cfg.aes_slots_new = false; h_cfg.rcm_patched = fuse_check_patched_rcm(); + h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; h_cfg.emummc_force_disable = false; h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; diff --git a/source/config.h b/source/config.h index 894cdf9..9a69d19 100644 --- a/source/config.h +++ b/source/config.h @@ -38,6 +38,7 @@ typedef struct _hekate_config bool aes_slots_new; bool emummc_force_disable; bool rcm_patched; + bool sbk_set; u32 errors; hos_eks_mbr_t *eks; } hekate_config; diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index 70a7292..db57ec1 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2018-2021 CTCaer + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -24,6 +24,8 @@ gfx_ctxt_t gfx_ctxt; gfx_con_t gfx_con; +static bool gfx_con_init_done = false; + static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) @@ -158,6 +160,8 @@ void gfx_con_init() gfx_con.fillbg = 1; gfx_con.bgcol = 0xFF1B1B1B; gfx_con.mute = 0; + + gfx_con_init_done = true; } void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) @@ -274,7 +278,7 @@ void gfx_putc(char c) void gfx_puts(const char *s) { - if (!s || gfx_con.mute) + if (!s || !gfx_con_init_done || gfx_con.mute) return; for (; *s; s++) @@ -330,7 +334,7 @@ void gfx_put_big_sep() void gfx_printf(const char *fmt, ...) { - if (gfx_con.mute) + if (!gfx_con_init_done || gfx_con.mute) return; va_list ap; @@ -404,11 +408,13 @@ void gfx_printf(const char *fmt, ...) va_end(ap); } -void gfx_hexdump(u32 base, const u8 *buf, u32 len) +void gfx_hexdump(u32 base, const void *buf, u32 len) { - if (gfx_con.mute) + if (!gfx_con_init_done || gfx_con.mute) return; + u8 *buff = (u8 *)buf; + u8 prevFontSize = gfx_con.fntsz; gfx_con.fntsz = 8; for(u32 i = 0; i < len; i++) @@ -420,7 +426,7 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_puts("| "); for(u32 j = 0; j < 0x10; j++) { - u8 c = buf[i - 0x10 + j]; + u8 c = buff[i - 0x10 + j]; if(c >= 32 && c <= 126) gfx_putc(c); else @@ -430,7 +436,7 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) } gfx_printf("%08x: ", base + i); } - gfx_printf("%02x ", buf[i]); + gfx_printf("%02x ", buff[i]); if (i == len - 1) { int ln = len % 0x10 != 0; @@ -444,7 +450,7 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_puts("| "); for(u32 j = 0; j < (ln ? k : k + 1); j++) { - u8 c = buf[i - k + j]; + u8 c = buff[i - k + j]; if(c >= 32 && c <= 126) gfx_putc(c); else @@ -457,12 +463,15 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_con.fntsz = prevFontSize; } -void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len) +void gfx_hexdiff(u32 base, const void *buf1, const void *buf2, u32 len) { - if (gfx_con.mute) + if (!gfx_con_init_done || gfx_con.mute) return; - if (memcmp(buf1, buf2, len) == 0) + u8 *buff1 = (u8 *)buf1; + u8 *buff2 = (u8 *)buf2; + + if (memcmp(buff1, buff2, len) == 0) { gfx_printf("Diff: No differences found.\n"); return; @@ -473,14 +482,14 @@ void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len) for(u32 i = 0; i < len; i+=0x10) { u32 bytes_left = len - i < 0x10 ? len - i : 0x10; - if (memcmp(buf1 + i, buf2 + i, bytes_left) == 0) + if (memcmp(buff1 + i, buff2 + i, bytes_left) == 0) continue; gfx_printf("Diff 1: %08x: ", base + i); for (u32 j = 0; j < bytes_left; j++) { - if (buf1[i+j] != buf2[i+j]) + if (buff1[i+j] != buff2[i+j]) gfx_con.fgcol = COLOR_ORANGE; - gfx_printf("%02x ", buf1[i+j]); + gfx_printf("%02x ", buff1[i+j]); gfx_con.fgcol = 0xFFCCCCCC; } gfx_puts("| "); @@ -488,9 +497,9 @@ void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len) gfx_printf("Diff 2: %08x: ", base + i); for (u32 j = 0; j < bytes_left; j++) { - if (buf1[i+j] != buf2[i+j]) + if (buff1[i+j] != buff2[i+j]) gfx_con.fgcol = COLOR_ORANGE; - gfx_printf("%02x ", buf2[i+j]); + gfx_printf("%02x ", buff2[i+j]); gfx_con.fgcol = 0xFFCCCCCC; } gfx_puts("| "); diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index 582cbbb..0f1c27b 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 CTCaer + * Copyright (c) 2019-2021 shchmue * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it @@ -63,8 +64,8 @@ void gfx_con_setpos(u32 x, u32 y); void gfx_putc(char c); void gfx_puts(const char *s); void gfx_printf(const char *fmt, ...); -void gfx_hexdump(u32 base, const u8 *buf, u32 len); -void gfx_hexdiff(u32 base, const u8 *buf1, const u8 *buf2, u32 len); +void gfx_hexdump(u32 base, const void *buf, u32 len); +void gfx_hexdiff(u32 base, const void *buf1, const void *buf2, u32 len); void gfx_set_pixel(u32 x, u32 y, u32 color); void gfx_line(int x0, int y0, int x1, int y1, u32 color); diff --git a/source/gfx/tui.c b/source/gfx/tui.c index 79be716..173178a 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include +#include #include "tui.h" #include "../config.h" #include @@ -77,7 +77,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) x += 7 * gfx_con.fntsz; - for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) + for (u32 i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) { gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol); gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol); diff --git a/source/hos/fss.c b/source/hos/fss.c index 09896f9..1521d82 100644 --- a/source/hos/fss.c +++ b/source/hos/fss.c @@ -139,7 +139,7 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) if (mariko_not_supported) { - EPRINTF("Mariko not supported on < 0.17.0!"); + EPRINTF("\nMariko not supported on < 0.17.0!"); goto fail; } diff --git a/source/hos/hos.h b/source/hos/hos.h index b5900c6..2b89bb3 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -20,6 +20,7 @@ #include "pkg1.h" #include "pkg2.h" +#include #include #include #include @@ -50,20 +51,21 @@ typedef struct _exo_ctxt_t bool fs_is_510; bool no_user_exceptions; bool user_pmu; + bool *usb3_force; bool *cal0_blank; bool *cal0_allow_writes_sys; } exo_ctxt_t; typedef struct _hos_eks_keys_t { - u8 mkk[0x10]; - u8 fdk[0x10]; + u8 mkk[SE_KEY_128_SIZE]; + u8 fdk[SE_KEY_128_SIZE]; } hos_eks_keys_t; typedef struct _hos_eks_bis_keys_t { - u8 crypt[0x10]; - u8 tweak[0x10]; + u8 crypt[SE_KEY_128_SIZE]; + u8 tweak[SE_KEY_128_SIZE]; } hos_eks_bis_keys_t; typedef struct _hos_eks_mbr_t @@ -73,8 +75,8 @@ typedef struct _hos_eks_mbr_t u8 enabled_bis; u8 rsvd[2]; u32 lot0; - u8 dkg[0x10]; - u8 dkk[0x10]; + u8 dkg[SE_KEY_128_SIZE]; + u8 dkk[SE_KEY_128_SIZE]; hos_eks_keys_t keys[5]; hos_eks_bis_keys_t bis_keys[3]; } hos_eks_mbr_t; @@ -106,14 +108,16 @@ typedef struct _launch_ctxt_t link_t kip1_list; char* kip1_patches; - u32 fss0_hosver; bool svcperm; bool debugmode; bool stock; - bool atmosphere; - bool fss0_experimental; bool emummc_forced; + char *fss0_main_path; + u32 fss0_hosver; + bool fss0_experimental; + bool atmosphere; + exo_ctxt_t exo_ctx; ini_sec_t *cfg; @@ -129,6 +133,6 @@ void hos_eks_get(); void hos_eks_save(u32 kb); void hos_eks_clear(u32 kb); int hos_launch(ini_sec_t *cfg); -int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); +int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); #endif diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 9cf549c..4800aff 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ static const pkg1_id_t _pkg1_ids[] = { const pkg1_id_t *pkg1_identify(u8 *pkg1) { - for (u32 i = 0; _pkg1_ids[i].id; i++) + for (u32 i = 0; i < ARRAY_SIZE(_pkg1_ids); i++) if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 8)) return &_pkg1_ids[i]; return NULL; diff --git a/source/hos/sept.c b/source/hos/sept.c index 94b86f6..873b7ab 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -21,7 +21,7 @@ #include "sept.h" #include "../config.h" #include -#include +#include #include #include #include diff --git a/source/keys/keys.c b/source/keys/keys.c index cfd3952..e634f57 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -17,7 +17,7 @@ #include "keys.h" #include "../config.h" -#include +#include #include #include "../gfx/tui.h" #include "../hos/pkg1.h" @@ -93,8 +93,8 @@ static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; } -static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { - if (emummc_storage_init_mmc(&emmc_storage, sdmmc)) { +static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { + if (emummc_storage_init_mmc()) { EPRINTF("Unable to init MMC."); return NULL; } @@ -102,11 +102,11 @@ static u8 *_read_pkg1(sdmmc_t *sdmmc, const pkg1_id_t **pkg1_id) { // Read package1. u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); - if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { + if (!emummc_storage_set_mmc_partition(EMMC_BOOT0)) { EPRINTF("Unable to set partition."); return NULL; } - if (!emummc_storage_read(&emmc_storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { + if (!emummc_storage_read(PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { EPRINTF("Unable to read pkg1."); return NULL; } @@ -283,7 +283,7 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); - if (!emummc_storage_read(&emmc_storage, KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { + if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblobs."); } @@ -577,7 +577,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit rsa_keypair_t rsa_keypair = {0}; - if (!emummc_storage_read(&emmc_storage, NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { + if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { EPRINTF("Unable to read PRODINFO."); return false; } @@ -643,7 +643,7 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit se_aes_key_set(4, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); se_aes_key_set(5, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); - if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { + if (!emummc_storage_set_mmc_partition(EMMC_GPP)) { EPRINTF("Unable to set partition."); return false; } @@ -690,7 +690,7 @@ static void _save_mariko_partial_keys(char *text_buffer) { for (u32 ks = 12; ks < 16; ks++) { // First, encrypt zeros with complete key se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros); - pos += sprintf(&text_buffer[pos], "%d\n", ks); + pos += s_printf(&text_buffer[pos], "%d\n", ks); // We only need to overwrite 3 of the dwords of the key for (u32 i = 0; i < 3; i++) { @@ -701,8 +701,8 @@ static void _save_mariko_partial_keys(char *text_buffer) { } for (u32 i = 0; i < 4; i++) { for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - pos += sprintf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]); - pos += sprintf(&text_buffer[pos], "\n"); + pos += s_printf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]); + pos += s_printf(&text_buffer[pos], "\n"); } } free(data); @@ -788,7 +788,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/prod.keys"; if (fuse_read_odm(4) & 3) - sprintf(&keyfile_path[11], "dev.keys"); + s_printf(&keyfile_path[11], "dev.keys"); FILINFO fno; if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { @@ -811,13 +811,13 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl for (u32 i = 0; i < _titlekey_count; i++) { for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - sprintf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); - sprintf(titlekey_text[i].equals, " = "); + s_printf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); + s_printf(titlekey_text[i].equals, " = "); for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - sprintf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); - sprintf(titlekey_text[i].newline, "\n"); + s_printf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); + s_printf(titlekey_text[i].newline, "\n"); } - sprintf(&keyfile_path[11], "title.keys"); + s_printf(&keyfile_path[11], "title.keys"); if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else @@ -828,10 +828,9 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl static void _derive_keys() { u32 start_whole_operation_time = get_tmr_us(); - sdmmc_t sdmmc; const pkg1_id_t *pkg1_id; - u8 *pkg1 = _read_pkg1(&sdmmc, &pkg1_id); + u8 *pkg1 = _read_pkg1(&pkg1_id); if (!pkg1) { return; } @@ -909,17 +908,17 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) if (!_key_exists(data)) return; u32 pos = strlen(outbuf); - pos += sprintf(&outbuf[pos], "%s = ", name); + pos += s_printf(&outbuf[pos], "%s = ", name); for (u32 i = 0; i < len; i++) - pos += sprintf(&outbuf[pos], "%02x", *(u8*)(data + i)); - sprintf(&outbuf[pos], "\n"); + pos += s_printf(&outbuf[pos], "%02x", *(u8*)(data + i)); + s_printf(&outbuf[pos], "\n"); _key_count++; } static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char *temp_name = calloc(1, 0x40); for (u32 i = 0; i < num_keys; i++) { - sprintf(temp_name, "%s_%02x", name, i + start_key); + s_printf(temp_name, "%s_%02x", name, i + start_key); _save_key(temp_name, data + i * len, len, outbuf); } free(temp_name); diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index 4b914b3..a8a39df 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -245,7 +245,7 @@ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2020 +#define FF_NORTC_YEAR 2021 /* The option FF_FS_NORTC switches timestamp function. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp diff --git a/source/link.ld b/source/link.ld index 65d681e..fe49b0c 100644 --- a/source/link.ld +++ b/source/link.ld @@ -5,7 +5,8 @@ SECTIONS { . = __ipl_start; .text : { *(.text._start); - *(._boot_cfg); + KEEP(*(._boot_cfg)); + *(.text._irq_setup); *(.text*); } .data : { diff --git a/source/main.c b/source/main.c index d304c8f..deee446 100644 --- a/source/main.c +++ b/source/main.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2018 naehrwert * - * Copyright (c) 2018-2020 CTCaer - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2018-2021 CTCaer + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,7 +20,7 @@ #include #include "config.h" -#include +#include #include #include "gfx/tui.h" #include @@ -57,6 +57,7 @@ volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; #define EXT_PAYLOAD_ADDR 0xC0000000 #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define COREBOOT_END_ADDR 0xD0000000 +#define COREBOOT_VER_OFF 0x41 #define CBFS_DRAM_EN_ADDR 0x4003e000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" @@ -80,9 +81,10 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) } } -int launch_payload(char *path) +int launch_payload(char *path, bool clear_screen) { - gfx_clear_grey(0x1B); + if (clear_screen) + gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); if (!path) return 1; @@ -92,10 +94,10 @@ int launch_payload(char *path) FIL fp; if (f_open(&fp, path, FA_READ)) { + gfx_con.mute = false; EPRINTFARGS("Payload file is missing!\n(%s)", path); - sd_unmount(); - return 1; + goto out; } // Read and copy the payload to our chosen address @@ -108,19 +110,27 @@ int launch_payload(char *path) { coreboot_addr = (void *)(COREBOOT_END_ADDR - size); buf = coreboot_addr; + if (h_cfg.t210b01) + { + f_close(&fp); + + gfx_con.mute = false; + EPRINTF("Coreboot not allowed on Mariko!"); + + goto out; + } } if (f_read(&fp, buf, size, NULL)) { f_close(&fp); - sd_unmount(); - return 1; + goto out; } f_close(&fp); - sd_unmount(); + sd_end(); if (size < 0x30000) { @@ -131,7 +141,12 @@ int launch_payload(char *path) else { reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); - hw_reinit_workaround(true, 0); + + // Get coreboot seamless display magic. + u32 magic = 0; + char *magic_ptr = buf + COREBOOT_VER_OFF; + memcpy(&magic, magic_ptr + strlen(magic_ptr) - 4, 4); + hw_reinit_workaround(true, magic); } // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. @@ -143,6 +158,8 @@ int launch_payload(char *path) (*ext_payload_ptr)(); } +out: + sd_end(); return 1; } @@ -221,7 +238,8 @@ void launch_tools() free(ments); free(dir); free(filelist); - sd_unmount(); + sd_end(); + return; } } @@ -247,15 +265,12 @@ void launch_tools() else memcpy(dir, file_sec, strlen(file_sec) + 1); - if (launch_payload(dir)) - { - EPRINTF("Failed to launch payload."); - free(dir); - } + launch_payload(dir, true); + EPRINTF("Failed to launch payload."); } out: - sd_unmount(); + sd_end(); free(dir); btn_wait(); @@ -278,15 +293,20 @@ void dump_emunand() dump_keys(); } +power_state_t STATE_POWER_OFF = POWER_OFF_RESET; +power_state_t STATE_REBOOT_FULL = POWER_OFF_REBOOT; +power_state_t STATE_REBOOT_RCM = REBOOT_RCM; +power_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES; + ment_t ment_top[] = { MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), MDEF_CAPTION("---------------", COLOR_YELLOW), MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), MDEF_CAPTION("---------------", COLOR_BLUE), - MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_VIOLET), - MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_RED), - MDEF_HANDLER("Power off", power_off, COLOR_ORANGE), + MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_VIOLET), + MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_RED), + MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_ORANGE), MDEF_END() }; @@ -305,7 +325,7 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset); if (pkg1_id) { - sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + s_printf(sysnand_label + 36, "% 3d", pkg1_id->kb); ment_top[0].caption = sysnand_label; if (h_cfg.emummc_force_disable) { @@ -314,15 +334,15 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) } } - emummc_storage_init_mmc(&storage, &sdmmc); + emummc_storage_init_mmc(); memset(pkg1, 0, PKG1_MAX_SIZE); - emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - emummc_storage_read(&storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); - emummc_storage_end(&storage); + emummc_storage_set_mmc_partition(EMMC_BOOT0); + emummc_storage_read(PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); + emummc_storage_end(); pkg1_id = pkg1_identify(pkg1 + pk1_offset); if (pkg1_id) { - sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + s_printf(emunand_label + 36, "% 3d", pkg1_id->kb); free(pkg1); ment_top[1].caption = emunand_label; } @@ -367,8 +387,9 @@ void ipl_main() display_backlight_pwm_init(); // Overclock BPMP. - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + bpmp_clk_rate_set(h_cfg.t210b01 ? BPMP_CLK_DEFAULT_BOOST : BPMP_CLK_LOWER_BOOST); + // Load emuMMC configuration from SD. emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; @@ -401,7 +422,7 @@ void ipl_main() if (h_cfg.rcm_patched) { - ment_top[5].handler = reboot_full; + ment_top[6].data = &STATE_REBOOT_FULL; } // Update key generations listed in menu. diff --git a/source/start.S b/source/start.S index 534f963..269f2c7 100644 --- a/source/start.S +++ b/source/start.S @@ -23,8 +23,8 @@ .extern memset .type memset, %function -.extern ipl_main -.type ipl_main, %function +.extern _irq_setup +.type _irq_setup, %function .globl _start .type _start, %function @@ -67,7 +67,7 @@ _real_start: LDR R2, =__bss_end SUB R2, R2, R0 BL memset - BL ipl_main + BL _irq_setup B . .globl pivot_stack diff --git a/source/storage/emummc.c b/source/storage/emummc.c index baa4560..52a748e 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 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, @@ -131,13 +131,13 @@ static int emummc_raw_get_part_off(int part_idx) return 2; } -int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +int emummc_storage_init_mmc() { FILINFO fno; emu_cfg.active_part = 0; // Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway. - if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) return 2; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) @@ -173,21 +173,21 @@ out: return 1; } -int emummc_storage_end(sdmmc_storage_t *storage) +int emummc_storage_end() { if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - sdmmc_storage_end(storage); + sdmmc_storage_end(&emmc_storage); else sd_end(); return 1; } -int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +int emummc_storage_read(u32 sector, u32 num_sectors, void *buf) { FIL fp; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - return sdmmc_storage_read(storage, sector, num_sectors, buf); + return sdmmc_storage_read(&emmc_storage, sector, num_sectors, buf); else if (emu_cfg.sector) { sector += emu_cfg.sector; @@ -228,11 +228,11 @@ int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, v return 1; } -int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +int emummc_storage_write(u32 sector, u32 num_sectors, void *buf) { FIL fp; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - return sdmmc_storage_write(storage, sector, num_sectors, buf); + return sdmmc_storage_write(&emmc_storage, sector, num_sectors, buf); else if (emu_cfg.sector) { sector += emu_cfg.sector; @@ -253,15 +253,13 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); } } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE)) - { - gfx_printf("e5\n"); return 0; - } + f_lseek(&fp, (u64)sector << 9); if (f_write(&fp, buf, (u64)num_sectors << 9, NULL)) { - gfx_printf("e6\n"); f_close(&fp); return 0; } @@ -271,13 +269,12 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, } } -int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +int emummc_storage_set_mmc_partition(u32 partition) { emu_cfg.active_part = partition; + sdmmc_storage_set_mmc_partition(&emmc_storage, partition); - if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - sdmmc_storage_set_mmc_partition(storage, partition); - else if (emu_cfg.sector) + if (!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.sector) return 1; else { diff --git a/source/storage/emummc.h b/source/storage/emummc.h index 81ad123..e8b1d32 100644 --- a/source/storage/emummc.h +++ b/source/storage/emummc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 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, @@ -51,10 +51,10 @@ extern emummc_cfg_t emu_cfg; void emummc_load_cfg(); bool emummc_set_path(char *path); -int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); -int emummc_storage_end(sdmmc_storage_t *storage); -int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); -int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); -int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +int emummc_storage_init_mmc(); +int emummc_storage_end(); +int emummc_storage_read(u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(u32 sector, u32 num_sectors, void *buf); +int emummc_storage_set_mmc_partition(u32 partition); #endif \ No newline at end of file diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index be7aa4b..223c449 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +20,7 @@ #include "nx_emmc.h" #include "emummc.h" #include +#include #include #include @@ -30,7 +32,11 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) { 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, gpt_buf); + emummc_storage_read(NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf); + + // Check if no GPT or more than max allowed entries. + if (memcmp(&gpt_buf->header.signature, "EFI PART", 8) || gpt_buf->header.num_part_ents > 128) + goto out; for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++) { @@ -52,6 +58,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) list_append(gpt, &part->link); } +out: free(gpt_buf); } @@ -66,6 +73,7 @@ emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name) LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link) if (!strcmp(part->name, name)) return part; + return NULL; } @@ -74,7 +82,8 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; - return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); + + return emummc_storage_read(part->lba_start + sector_off, num_sectors, buf); } int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) @@ -82,5 +91,20 @@ int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_o // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; - return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf); + + return emummc_storage_write(part->lba_start + sector_off, num_sectors, buf); +} + +void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1) +{ + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD) + { + *mod0 = 0xF7; + *mod1 = 0x86; + } + else + { + *mod0 = 0x37; + *mod1 = 0x84; + } } diff --git a/source/storage/nx_emmc.h b/source/storage/nx_emmc.h index 5db6a1f..f89f526 100644 --- a/source/storage/nx_emmc.h +++ b/source/storage/nx_emmc.h @@ -1,5 +1,6 @@ /* * 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, @@ -43,7 +44,9 @@ extern FATFS emmc_fs; void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage); void nx_emmc_gpt_free(link_t *gpt); emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name); -int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); -int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); +int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); +int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); + +void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1); #endif diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index a2d19c2..1362274 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -23,6 +23,7 @@ #include #include +#include #include "../storage/nx_emmc.h" #include "nx_emmc_bis.h" #include @@ -32,7 +33,7 @@ #define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF #define SECTORS_PER_CLUSTER 0x20 -typedef struct +typedef struct _cluster_cache_t { u32 cluster_num; // index of the cluster in the partition u32 visit_count; // used for debugging/access analysis @@ -41,7 +42,7 @@ typedef struct u8 cluster[XTS_CLUSTER_SIZE]; // the cached cluster itself } cluster_cache_t; -typedef struct +typedef struct _bis_cache_t { u8 emmc_buffer[XTS_CLUSTER_SIZE]; cluster_cache_t cluster_cache[]; @@ -313,8 +314,8 @@ void nx_emmc_bis_cluster_cache_init() free(cluster_lookup_buf); // Check if carveout protected, in case of old hwinit (pre 4.0.0) chainload. - *(vu32 *)NX_BIS_LOOKUP_ADR = 0; - if (*(vu32 *)NX_BIS_LOOKUP_ADR != 0) + *(vu32 *)NX_BIS_LOOKUP_ADDR = 0; + if (*(vu32 *)NX_BIS_LOOKUP_ADDR != 0) { cluster_lookup_buf = (u32 *)malloc(cluster_lookup_size + 0x2000); cluster_lookup = (u32 *)ALIGN((u32)cluster_lookup_buf, 0x1000); @@ -322,7 +323,7 @@ void nx_emmc_bis_cluster_cache_init() else { cluster_lookup_buf = NULL; - cluster_lookup = (u32 *)NX_BIS_LOOKUP_ADR; + cluster_lookup = (u32 *)NX_BIS_LOOKUP_ADDR; } // Clear cluster lookup table and reset end index. diff --git a/source/storage/nx_sd.c b/source/storage/nx_sd.c index fa284fa..f2cec2f 100644 --- a/source/storage/nx_sd.c +++ b/source/storage/nx_sd.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 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, @@ -59,6 +59,11 @@ bool sd_get_card_removed() return false; } +bool sd_get_card_mounted() +{ + return sd_mounted; +} + u32 sd_get_mode() { return sd_mode; @@ -180,6 +185,11 @@ static void _sd_deinit() void sd_unmount() { _sd_deinit(); } void sd_end() { _sd_deinit(); } +bool sd_is_gpt() +{ + return sd_fs.part_type; +} + void *sd_file_read(const char *path, u32 *fsize) { FIL fp; From 918b00ce0734c9b4b7b34f7609ad2a35d59a5b02 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 16:47:06 -0600 Subject: [PATCH 105/166] Implement payload compression --- .gitignore | 11 +- Makefile | 70 +++-- Versions.inc | 4 + bdk/mem/mc.c | 2 +- bdk/memory_map.h | 4 +- loader/Makefile | 65 +++++ loader/link.ld | 21 ++ loader/loader.c | 101 +++++++ loader/start.S | 73 +++++ source/keys/keys.c | 4 +- tools/bin2c/Makefile | 16 ++ tools/bin2c/bin2c.c | 83 ++++++ tools/emc.def | 641 ++++++++++++++++++++++++++++++++++++++++++ tools/fix_regs.py | 36 +++ tools/lz/Makefile | 16 ++ tools/lz/lz.c | 546 +++++++++++++++++++++++++++++++++++ tools/lz/lz.h | 61 ++++ tools/lz/lz77.c | 93 ++++++ tools/mc.def | 448 +++++++++++++++++++++++++++++ tools/smmu_payload.py | 38 +++ 20 files changed, 2305 insertions(+), 28 deletions(-) create mode 100644 Versions.inc create mode 100644 loader/Makefile create mode 100644 loader/link.ld create mode 100644 loader/loader.c create mode 100644 loader/start.S create mode 100644 tools/bin2c/Makefile create mode 100644 tools/bin2c/bin2c.c create mode 100644 tools/emc.def create mode 100644 tools/fix_regs.py create mode 100644 tools/lz/Makefile create mode 100644 tools/lz/lz.c create mode 100644 tools/lz/lz.h create mode 100644 tools/lz/lz77.c create mode 100644 tools/mc.def create mode 100644 tools/smmu_payload.py diff --git a/.gitignore b/.gitignore index 5dfc71c..7592fed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ +.vs .vscode -build -output -research +build/* +output/* +research/* +loader/payload_00.h +loader/payload_01.h +tools/bin2c/bin2c +tools/lz/lz77 diff --git a/Makefile b/Makefile index a7efda8..94d81f3 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,8 @@ include $(DEVKITARM)/base_rules ################################################################################ -IPL_LOAD_ADDR := 0x40003000 -LPVERSION_MAJOR := 1 -LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 1 +IPL_LOAD_ADDR := 0x40008000 +include ./Versions.inc ################################################################################ @@ -40,52 +38,84 @@ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) -# 0: UART_A, 1: UART_B. -#CUSTOMDEFINES += -DDEBUG_UART_PORT=0 - #CUSTOMDEFINES += -DDEBUG +# UART Logging: Max baudrate 12.5M. +# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C. +#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=0 + #TODO: Considering reinstating some of these when pointer warnings have been fixed. WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) +LDRDIR := $(wildcard loader) +TOOLSLZ := $(wildcard tools/lz) +TOOLSB2C := $(wildcard tools/bin2c) +TOOLS := $(TOOLSLZ) $(TOOLSB2C) + ################################################################################ -.PHONY: all clean +.PHONY: all clean $(LDRDIR) $(TOOLS) -all: $(OUTPUTDIR)/$(TARGET).bin - @echo -n "Payload size is " +all: $(OUTPUTDIR)/$(TARGET).bin $(LDRDIR) + @echo "--------------------------------------" + @echo -n "Uncompr size: " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET)_unc.bin)) + @echo $(BIN_SIZE)" Bytes" + @echo "Uncompr Max: 140288 Bytes + 3 KiB BSS" + @if [ ${BIN_SIZE} -gt 140288 ]; then echo "\e[1;33mUncompr size exceeds limit!\e[0m"; fi + @echo -n "Payload size: " $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) - @echo $(BIN_SIZE) - @echo "Max size is 126296 Bytes." + @echo $(BIN_SIZE)" Bytes" + @echo "Payload Max: 126296 Bytes" @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi + @echo "--------------------------------------" -clean: +clean: $(TOOLS) @rm -rf $(BUILDDIR) @rm -rf $(OUTPUTDIR) -$(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf +$(LDRDIR): $(OUTPUTDIR)/$(TARGET).bin + @$(TOOLSLZ)/lz77 $(OUTPUTDIR)/$(TARGET).bin + mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(TARGET)_unc.bin + @mv $(OUTPUTDIR)/$(TARGET).bin.00.lz payload_00 + @mv $(OUTPUTDIR)/$(TARGET).bin.01.lz payload_01 + @$(TOOLSB2C)/bin2c payload_00 > $(LDRDIR)/payload_00.h + @$(TOOLSB2C)/bin2c payload_01 > $(LDRDIR)/payload_01.h + @rm payload_00 + @rm payload_01 + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) PAYLOAD_NAME=$(TARGET) + +$(TOOLS): + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) + +$(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(TOOLS) @mkdir -p "$(@D)" $(OBJCOPY) -S -O binary $< $@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) - $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @echo "Lockpick_RCM was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS) $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c @mkdir -p "$(@D)" - $(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.S @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c @mkdir -p "$(@D)" - $(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) -c $< -o $@ diff --git a/Versions.inc b/Versions.inc new file mode 100644 index 0000000..4f56f2c --- /dev/null +++ b/Versions.inc @@ -0,0 +1,4 @@ +# LP Version. +LPVERSION_MAJOR := 1 +LPVERSION_MINOR := 9 +LPVERSION_BUGFX := 1 diff --git a/bdk/mem/mc.c b/bdk/mem/mc.c index 4db3a30..c695987 100644 --- a/bdk/mem/mc.c +++ b/bdk/mem/mc.c @@ -20,7 +20,7 @@ #include #include -#define CONFIG_ENABLE_AHB_REDIRECT +//#define CONFIG_ENABLE_AHB_REDIRECT void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock) { diff --git a/bdk/memory_map.h b/bdk/memory_map.h index d0bfd7b..70f1354 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -19,10 +19,10 @@ //#define IPL_STACK_TOP 0x4003FF00 /* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ -/* --- IPL: 0x40003000 - 0x40028000 --- */ +/* --- IPL: 0x40008000 - 0x40028000 --- */ #define LDR_LOAD_ADDR 0x40007000 -#define IPL_LOAD_ADDR 0x40003000 +#define IPL_LOAD_ADDR 0x40008000 #define IPL_SZ_MAX 0x20000 // 128KB. /* --- XUSB EP context and TRB ring buffers --- */ diff --git a/loader/Makefile b/loader/Makefile new file mode 100644 index 0000000..d59ed08 --- /dev/null +++ b/loader/Makefile @@ -0,0 +1,65 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/base_rules + +################################################################################ + +LDR_LOAD_ADDR := 0x40007000 +IPL_MAGIC := 0x43544349 #"ICTC" +include ../Versions.inc + +################################################################################ + +TARGET := loader +BUILDDIR := ../build +OUTPUTDIR := ../output +BDKDIR := bdk +BDKINC := -I../$(BDKDIR) +VPATH += $(dir $(wildcard ../$(BDKDIR)/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/)) + +# Main and graphics. +OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ + start.o loader.o lz.o \ +) + +################################################################################ + +CUSTOMDEFINES := -DBL_MAGIC=$(IPL_MAGIC) +CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD) + +#TODO: Considering reinstating some of these when pointer warnings have been fixed. +WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overflow + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +CFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=LDR_LOAD_ADDR=$(LDR_LOAD_ADDR) + +################################################################################ + +.PHONY: all clean + +all: $(TARGET).bin $(TOOLSLZ) $(TOOLSB2C) + +clean: + @rm -rf $(OBJS) + +$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf + $(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(PAYLOAD_NAME).bin + +$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) + @$(CC) $(LDFLAGS) -T link.ld $^ -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.c + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.S + @$(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): $(BUILDDIR)/$(TARGET) + +$(BUILDDIR)/$(TARGET): + @mkdir -p "$(BUILDDIR)" + @mkdir -p "$(BUILDDIR)/$(TARGET)" + @mkdir -p "$(OUTPUTDIR)" diff --git a/loader/link.ld b/loader/link.ld new file mode 100644 index 0000000..1196fd4 --- /dev/null +++ b/loader/link.ld @@ -0,0 +1,21 @@ +ENTRY(_start) + +SECTIONS { + PROVIDE(__ipl_start = LDR_LOAD_ADDR); + . = __ipl_start; + .text : { + *(.text._start); + KEEP(*(._boot_cfg)); + KEEP(*(._octopus)); + *(.text*); + } + .data : { + *(.data*); + *(.rodata*); + *(._payload_00); + *(._payload_01); + } + __ldr_end = .; + . = ALIGN(0x10); + __ipl_end = .; +} diff --git a/loader/loader.c b/loader/loader.c new file mode 100644 index 0000000..5ec2060 --- /dev/null +++ b/loader/loader.c @@ -0,0 +1,101 @@ +/* + * 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 . + */ + +#include +#include + +#include "payload_00.h" +#include "payload_01.h" + +#include +#include +#include +#include + +// 0x4003D000: Safe for panic preserving, 0x40038000: Safe for debugging needs. +#define IPL_RELOC_TOP 0x40038000 +#define IPL_PATCHED_RELOC_SZ 0x94 + +boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; + +const volatile char __attribute__((section ("._octopus"))) octopus[] = + "\n" + " ___\n" + " .-' `'.\n" + " / \\\n" + " | ;\n" + " | | ___.--,\n" + " _.._ |0) = (0) | _.---'`__.-( (_.\n" + " __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n" + " ( ,.--'` ',__ /./; ;, '.__.'` __\n" + " _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n" + " `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n" + " | | .' _.-' | | \\ \\ '. `----`\n" + " \\ \\/ .' \\ \\ '. '-._)\n" + " \\/ / \\ \\ `=.__`'-.\n" + " / /\\ `) ) / / `\"\".`\\\n" + " , _.-'.'\\ \\ / / ( ( / /\n" + " `--'` ) ) .-'.' '.'. | (\n" + " (/` ( (` ) ) '-; [switchbrew]\n"; + +void loader_main() +{ + // Preliminary BPMP clocks init. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). + + // Get Loader and Payload size. + u32 payload_size = sizeof(payload_00) + sizeof(payload_01); // Actual payload size. + payload_size += (u32)payload_01 - (u32)payload_00 - sizeof(payload_00); // Add array alignment. + u32 *payload_addr = (u32 *)payload_00; + + // Relocate payload to a safer place. + u32 bytes = ALIGN(payload_size, 4) >> 2; + u32 *addr = payload_addr + bytes - 1; + u32 *dst = (u32 *)(IPL_RELOC_TOP - 4); + while (bytes) + { + *dst = *addr; + dst--; + addr--; + bytes--; + } + + // Set source address of the first part. + u8 *src_addr = (void *)(IPL_RELOC_TOP - ALIGN(payload_size, 4)); + // Uncompress first part. + u32 dst_pos = LZ_Uncompress((const u8 *)src_addr, (u8*)IPL_LOAD_ADDR, sizeof(payload_00)); + + // Set source address of the second part. Includes array alignment. + src_addr += (u32)payload_01 - (u32)payload_00; + // Uncompress second part. + LZ_Uncompress((const u8 *)src_addr, (u8*)IPL_LOAD_ADDR + dst_pos, sizeof(payload_01)); + + // Copy over boot configuration storage. + memcpy((u8 *)(IPL_LOAD_ADDR + IPL_PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); + + // Chainload into uncompressed payload. + void (*ipl_ptr)() = (void *)IPL_LOAD_ADDR; + (*ipl_ptr)(); + + // Halt if we managed to get out of execution. + while (true) + ; +} diff --git a/loader/start.S b/loader/start.S new file mode 100644 index 0000000..1d7a661 --- /dev/null +++ b/loader/start.S @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +.section .text._start +.arm + +.extern _reloc_ipl +.type _reloc_ipl, %function + +.extern memset +.type memset, %function + +.extern loader_main +.type loader_main, %function + +.globl _start +.type _start, %function +_start: + ADR R0, _start + LDR R1, =__ipl_start + CMP R0, R1 + BEQ _real_start + + /* If we are not in the right location already, copy a relocator to upper IRAM. */ + ADR R2, _reloc_ipl + LDR R3, =0x4003FF00 + MOV R4, #(_real_start - _reloc_ipl) +_copy_loop: + LDMIA R2!, {R5} + STMIA R3!, {R5} + SUBS R4, #4 + BNE _copy_loop + + /* Use the relocator to copy ourselves into the right place. */ + LDR R2, =__ipl_end + SUB R2, R2, R1 + LDR R3, =_real_start + LDR R4, =0x4003FF00 + BX R4 + +_reloc_ipl: + LDMIA R0!, {R4-R7} + STMIA R1!, {R4-R7} + SUBS R2, #0x10 + BNE _reloc_ipl + /* Jump to the relocated entry. */ + BX R3 + +_real_start: + /* Initially, we place our stack in IRAM but will move it to SDRAM later. */ + LDR SP, =0x40007000 + LDR R0, =__ldr_end + BL loader_main + B . + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 diff --git a/source/keys/keys.c b/source/keys/keys.c index e634f57..7b8fa8b 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -202,7 +202,7 @@ static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx int res = 0; u32 retries = 0; - mc_disable_ahb_redirect(); + // mc_disable_ahb_redirect(); while (tsec_query(keys->tsec_keys, kb, tsec_ctxt) < 0) { memset(keys->tsec_keys, 0, sizeof(keys->tsec_keys)); @@ -213,7 +213,7 @@ static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx } } - mc_enable_ahb_redirect(); + // mc_enable_ahb_redirect(); if (res < 0) { EPRINTFARGS("ERROR %x dumping TSEC.\n", res); diff --git a/tools/bin2c/Makefile b/tools/bin2c/Makefile new file mode 100644 index 0000000..e870ac8 --- /dev/null +++ b/tools/bin2c/Makefile @@ -0,0 +1,16 @@ +NATIVE_CC ?= gcc + +ifeq (, $(shell which $(NATIVE_CC) 2>/dev/null)) +$(error "Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=") +endif + +.PHONY: all clean + +all: bin2c + @echo > /dev/null + +clean: + @rm -f bin2c + +bin2c: bin2c.c + @$(NATIVE_CC) -o $@ bin2c.c diff --git a/tools/bin2c/bin2c.c b/tools/bin2c/bin2c.c new file mode 100644 index 0000000..0d820fc --- /dev/null +++ b/tools/bin2c/bin2c.c @@ -0,0 +1,83 @@ +/* + * This is bin2c program, which allows you to convert binary file to + * C language array, for use as embedded resource, for instance you can + * embed graphics or audio file directly into your program. + * This is public domain software, use it on your own risk. + * Contact Serge Fukanchik at fuxx@mail.ru if you have any questions. + */ + +#include +#include +#include +#include +#include + +/* Replace . with _ */ +char* +make_ident ( char* name ) +{ + char* ret; + char* p; + + ret = strdup ( name ); + + for ( p = ret; p[0]; p++ ) + { + if ( !isalnum ( p[0] ) ) p[0] = '_'; + } + return ret; +} + +int +main ( int argc, char* argv[] ) +{ + unsigned char buf[BUFSIZ]; + char* ident; + FILE *fd; + size_t size, i, total, blksize = BUFSIZ; + int need_comma = 0; + + if ( argc != 2 ) + { + fprintf ( stderr, "Usage: %s binary_file > output_file\n", argv[0] ); + return -1; + } + + fd = fopen ( argv[1], "rb" ); + if ( fd == NULL ) + { + fprintf ( stderr, "%s: can't open %s for reading\n", argv[0], argv[1] ); + return -1; + } + + fseek(fd, 0, SEEK_END); + size = ftell(fd); + rewind(fd); + + ident = make_ident ( argv[1] ); + + printf ( "static const unsigned char __attribute__((section (\"._%s\"))) %s[] = {", ident, ident ); + for ( total = 0; total < size; ) + { + if ( size - total < blksize ) blksize = size - total; + if ( fread ( buf, 1, blksize, fd ) != blksize ) + { + fprintf ( stderr, "%s: file read error\n", argv[0] ); + return -1; + } + for ( i = 0; i < blksize; i++ ) + { + if ( need_comma ) printf ( ", " ); + else need_comma = 1; + if ( ( total % 11 ) == 0 ) printf ( "\n\t" ); + printf ( "0x%.2x", buf[i] ); + total++; + } + } + printf ( "\n};\n" ); + + fclose ( fd ); + free ( ident ); + + return 0; +} diff --git a/tools/emc.def b/tools/emc.def new file mode 100644 index 0000000..ddcb5af --- /dev/null +++ b/tools/emc.def @@ -0,0 +1,641 @@ +EMC_DBG 8 +EMC_CFG C +EMC_CONFIG_SAMPLE_DELAY 5f0 +EMC_CFG_UPDATE 5f4 +EMC_ADR_CFG 10 +EMC_REFCTRL 20 +EMC_PIN 24 +EMC_TIMING_CONTROL 28 +EMC_RC 2c +EMC_RFC 30 +EMC_RFCPB 590 +EMC_RAS 34 +EMC_RP 38 +EMC_R2W 3c +EMC_W2R 40 +EMC_R2P 44 +EMC_W2P 48 +EMC_CCDMW 5c0 +EMC_RD_RCD 4c +EMC_WR_RCD 50 +EMC_RRD 54 +EMC_REXT 58 +EMC_WDV 5c +EMC_QUSE 60 +EMC_QRST 64 +EMC_ISSUE_QRST 428 +EMC_QSAFE 68 +EMC_RDV 6c +EMC_REFRESH 70 +EMC_BURST_REFRESH_NUM 74 +EMC_PDEX2WR 78 +EMC_PDEX2RD 7c +EMC_PDEX2CKE 118 +EMC_PCHG2PDEN 80 +EMC_ACT2PDEN 84 +EMC_AR2PDEN 88 +EMC_RW2PDEN 8c +EMC_CKE2PDEN 11c +EMC_TXSR 90 +EMC_TCKE 94 +EMC_TFAW 98 +EMC_TRPAB 9c +EMC_TCLKSTABLE a0 +EMC_TCLKSTOP a4 +EMC_TREFBW a8 +EMC_TPPD ac +EMC_PDEX2MRR b4 +EMC_ODT_WRITE b0 +EMC_WEXT b8 +EMC_RFC_SLR c0 +EMC_MRS_WAIT_CNT2 c4 +EMC_MRS_WAIT_CNT c8 +EMC_MRS cc +EMC_EMRS d0 +EMC_REF d4 +EMC_PRE d8 +EMC_NOP dc +EMC_SELF_REF e0 +EMC_DPD e4 +EMC_MRW e8 +EMC_MRR ec +EMC_CMDQ f0 +EMC_MC2EMCQ f4 +EMC_FBIO_SPARE 100 +EMC_FBIO_CFG5 104 +EMC_CFG_RSV 120 +EMC_ACPD_CONTROL 124 +EMC_MPC 128 +EMC_EMRS2 12c +EMC_EMRS3 130 +EMC_MRW2 134 +EMC_MRW3 138 +EMC_MRW4 13c +EMC_MRW5 4a0 +EMC_MRW6 4a4 +EMC_MRW7 4a8 +EMC_MRW8 4ac +EMC_MRW9 4b0 +EMC_MRW10 4b4 +EMC_MRW11 4b8 +EMC_MRW12 4bc +EMC_MRW13 4c0 +EMC_MRW14 4c4 +EMC_MRW15 4d0 +EMC_CFG_SYNC 4d4 +EMC_CLKEN_OVERRIDE 140 +EMC_R2R 144 +EMC_W2W 148 +EMC_EINPUT 14c +EMC_EINPUT_DURATION 150 +EMC_PUTERM_EXTRA 154 +EMC_TCKESR 158 +EMC_TPD 15c +EMC_STAT_CONTROL 160 +EMC_STAT_STATUS 164 +EMC_STAT_DRAM_CLOCK_LIMIT_LO 19c +EMC_STAT_DRAM_CLOCK_LIMIT_HI 1a0 +EMC_STAT_DRAM_CLOCKS_LO 1a4 +EMC_STAT_DRAM_CLOCKS_HI 1a8 +EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 1ac +EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 1b0 +EMC_STAT_DRAM_DEV0_READ_CNT_LO 1b4 +EMC_STAT_DRAM_DEV0_READ_CNT_HI 1b8 +EMC_STAT_DRAM_DEV0_READ8_CNT_LO 1bc +EMC_STAT_DRAM_DEV0_READ8_CNT_HI 1c0 +EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 1c4 +EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 1c8 +EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 1cc +EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 1d0 +EMC_STAT_DRAM_DEV0_REF_CNT_LO 1d4 +EMC_STAT_DRAM_DEV0_REF_CNT_HI 1d8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1dc +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e0 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1e4 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1ec +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f0 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1f4 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 1fc +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 200 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 204 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 208 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 20c +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 210 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 214 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 218 +EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 21c +EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 220 +EMC_STAT_DRAM_DEV0_DSR 224 +EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 228 +EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 22c +EMC_STAT_DRAM_DEV1_READ_CNT_LO 230 +EMC_STAT_DRAM_DEV1_READ_CNT_HI 234 +EMC_STAT_DRAM_DEV1_READ8_CNT_LO 238 +EMC_STAT_DRAM_DEV1_READ8_CNT_HI 23c +EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 240 +EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 244 +EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 248 +EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 24c +EMC_STAT_DRAM_DEV1_REF_CNT_LO 250 +EMC_STAT_DRAM_DEV1_REF_CNT_HI 254 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 258 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 25c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 260 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 264 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 268 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 26c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 270 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 274 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 278 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 27c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 280 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 284 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 288 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 28c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 290 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 294 +EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 298 +EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 29c +EMC_STAT_DRAM_DEV1_DSR 2a0 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c8c +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c90 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c94 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c98 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO c9c +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO ca4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca8 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cac +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cb4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb8 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cbc +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cc4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc8 +EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO ccc +EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI cd0 +EMC_STAT_DRAM_IO_DSR cd4 +EMC_AUTO_CAL_CONFIG 2a4 +EMC_AUTO_CAL_CONFIG2 458 +EMC_AUTO_CAL_CONFIG3 45c +EMC_AUTO_CAL_CONFIG4 5b0 +EMC_AUTO_CAL_CONFIG5 5b4 +EMC_AUTO_CAL_CONFIG6 5cc +EMC_AUTO_CAL_CONFIG7 574 +EMC_AUTO_CAL_CONFIG8 2dc +EMC_AUTO_CAL_VREF_SEL_0 2f8 +EMC_AUTO_CAL_VREF_SEL_1 300 +EMC_AUTO_CAL_INTERVAL 2a8 +EMC_AUTO_CAL_STATUS 2ac +EMC_AUTO_CAL_STATUS2 3d4 +EMC_AUTO_CAL_CHANNEL 464 +EMC_PMACRO_RX_TERM c48 +EMC_PMACRO_DQ_TX_DRV c70 +EMC_PMACRO_CA_TX_DRV c74 +EMC_PMACRO_CMD_TX_DRV c4c +EMC_PMACRO_AUTOCAL_CFG_0 700 +EMC_PMACRO_AUTOCAL_CFG_1 704 +EMC_PMACRO_AUTOCAL_CFG_2 708 +EMC_PMACRO_AUTOCAL_CFG_COMMON c78 +EMC_PMACRO_ZCTRL c44 +EMC_XM2COMPPADCTRL 30c +EMC_XM2COMPPADCTRL2 578 +EMC_XM2COMPPADCTRL3 2f4 +EMC_COMP_PAD_SW_CTRL 57c +EMC_REQ_CTRL 2b0 +EMC_EMC_STATUS 2b4 +EMC_CFG_2 2b8 +EMC_CFG_DIG_DLL 2bc +EMC_CFG_DIG_DLL_PERIOD 2c0 +EMC_DIG_DLL_STATUS 2c4 +EMC_CFG_DIG_DLL_1 2c8 +EMC_RDV_MASK 2cc +EMC_WDV_MASK 2d0 +EMC_RDV_EARLY_MASK 2d4 +EMC_RDV_EARLY 2d8 +EMC_WDV_CHK 4e0 +EMC_ZCAL_INTERVAL 2e0 +EMC_ZCAL_WAIT_CNT 2e4 +EMC_ZCAL_MRW_CMD 2e8 +EMC_ZQ_CAL 2ec +EMC_SCRATCH0 324 +EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 3c8 +EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 3cc +EMC_UNSTALL_RW_AFTER_CLKCHANGE 3d0 +EMC_FDPD_CTRL_CMD_NO_RAMP 4d8 +EMC_SEL_DPD_CTRL 3d8 +EMC_FDPD_CTRL_DQ 310 +EMC_FDPD_CTRL_CMD 314 +EMC_PRE_REFRESH_REQ_CNT 3dc +EMC_REFCTRL2 580 +EMC_FBIO_CFG7 584 +EMC_DATA_BRLSHFT_0 588 +EMC_DATA_BRLSHFT_1 58c +EMC_DQS_BRLSHFT_0 594 +EMC_DQS_BRLSHFT_1 598 +EMC_CMD_BRLSHFT_0 59c +EMC_CMD_BRLSHFT_1 5a0 +EMC_CMD_BRLSHFT_2 5a4 +EMC_CMD_BRLSHFT_3 5a8 +EMC_QUSE_BRLSHFT_0 5ac +EMC_QUSE_BRLSHFT_1 5b8 +EMC_QUSE_BRLSHFT_2 5bc +EMC_QUSE_BRLSHFT_3 5c4 +EMC_FBIO_CFG8 5c8 +EMC_CMD_MAPPING_CMD0_0 380 +EMC_CMD_MAPPING_CMD0_1 384 +EMC_CMD_MAPPING_CMD0_2 388 +EMC_CMD_MAPPING_CMD1_0 38c +EMC_CMD_MAPPING_CMD1_1 390 +EMC_CMD_MAPPING_CMD1_2 394 +EMC_CMD_MAPPING_CMD2_0 398 +EMC_CMD_MAPPING_CMD2_1 39c +EMC_CMD_MAPPING_CMD2_2 3a0 +EMC_CMD_MAPPING_CMD3_0 3a4 +EMC_CMD_MAPPING_CMD3_1 3a8 +EMC_CMD_MAPPING_CMD3_2 3ac +EMC_CMD_MAPPING_BYTE 3b0 +EMC_DYN_SELF_REF_CONTROL 3e0 +EMC_TXSRDLL 3e4 +EMC_CCFIFO_ADDR 3e8 +EMC_CCFIFO_DATA 3ec +EMC_CCFIFO_STATUS 3f0 +EMC_SWIZZLE_RANK0_BYTE0 404 +EMC_SWIZZLE_RANK0_BYTE1 408 +EMC_SWIZZLE_RANK0_BYTE2 40c +EMC_SWIZZLE_RANK0_BYTE3 410 +EMC_SWIZZLE_RANK1_BYTE0 418 +EMC_SWIZZLE_RANK1_BYTE1 41c +EMC_SWIZZLE_RANK1_BYTE2 420 +EMC_SWIZZLE_RANK1_BYTE3 424 +EMC_TR_TIMING_0 3b4 +EMC_TR_CTRL_0 3b8 +EMC_TR_CTRL_1 3bc +EMC_TR_DVFS 460 +EMC_SWITCH_BACK_CTRL 3c0 +EMC_TR_RDV 3c4 +EMC_TR_QPOP 3f4 +EMC_TR_RDV_MASK 3f8 +EMC_TR_QSAFE 3fc +EMC_TR_QRST 400 +EMC_IBDLY 468 +EMC_OBDLY 46c +EMC_TXDSRVTTGEN 480 +EMC_WE_DURATION 48c +EMC_WS_DURATION 490 +EMC_WEV 494 +EMC_WSV 498 +EMC_CFG_3 49c +EMC_CFG_PIPE_2 554 +EMC_CFG_PIPE_CLK 558 +EMC_CFG_PIPE_1 55c +EMC_CFG_PIPE 560 +EMC_QPOP 564 +EMC_QUSE_WIDTH 568 +EMC_PUTERM_WIDTH 56c +EMC_PROTOBIST_CONFIG_ADR_1 5d0 +EMC_PROTOBIST_CONFIG_ADR_2 5d4 +EMC_PROTOBIST_MISC 5d8 +EMC_PROTOBIST_WDATA_LOWER 5dc +EMC_PROTOBIST_WDATA_UPPER 5e0 +EMC_PROTOBIST_RDATA 5ec +EMC_DLL_CFG_0 5e4 +EMC_DLL_CFG_1 5e8 +EMC_TRAINING_CMD e00 +EMC_TRAINING_CTRL e04 +EMC_TRAINING_STATUS e08 +EMC_TRAINING_QUSE_CORS_CTRL e0c +EMC_TRAINING_QUSE_FINE_CTRL e10 +EMC_TRAINING_QUSE_CTRL_MISC e14 +EMC_TRAINING_WRITE_FINE_CTRL e18 +EMC_TRAINING_WRITE_CTRL_MISC e1c +EMC_TRAINING_WRITE_VREF_CTRL e20 +EMC_TRAINING_READ_FINE_CTRL e24 +EMC_TRAINING_READ_CTRL_MISC e28 +EMC_TRAINING_READ_VREF_CTRL e2c +EMC_TRAINING_CA_FINE_CTRL e30 +EMC_TRAINING_CA_CTRL_MISC e34 +EMC_TRAINING_CA_CTRL_MISC1 e38 +EMC_TRAINING_CA_VREF_CTRL e3c +EMC_TRAINING_CA_TADR_CTRL e40 +EMC_TRAINING_SETTLE e44 +EMC_TRAINING_DEBUG_CTRL e48 +EMC_TRAINING_DEBUG_DQ0 e4c +EMC_TRAINING_DEBUG_DQ1 e50 +EMC_TRAINING_DEBUG_DQ2 e54 +EMC_TRAINING_DEBUG_DQ3 e58 +EMC_TRAINING_MPC e5c +EMC_TRAINING_PATRAM_CTRL e60 +EMC_TRAINING_PATRAM_DQ e64 +EMC_TRAINING_PATRAM_DMI e68 +EMC_TRAINING_VREF_SETTLE e6c +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 e70 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 e74 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 e78 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 e7c +EMC_TRAINING_RW_EYE_CENTER_IB_MISC e80 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 e84 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 e88 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 e8c +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 e90 +EMC_TRAINING_RW_EYE_CENTER_OB_MISC e94 +EMC_TRAINING_RW_OFFSET_IB_BYTE0 e98 +EMC_TRAINING_RW_OFFSET_IB_BYTE1 e9c +EMC_TRAINING_RW_OFFSET_IB_BYTE2 ea0 +EMC_TRAINING_RW_OFFSET_IB_BYTE3 ea4 +EMC_TRAINING_RW_OFFSET_IB_MISC ea8 +EMC_TRAINING_RW_OFFSET_OB_BYTE0 eac +EMC_TRAINING_RW_OFFSET_OB_BYTE1 eb0 +EMC_TRAINING_RW_OFFSET_OB_BYTE2 eb4 +EMC_TRAINING_RW_OFFSET_OB_BYTE3 eb8 +EMC_TRAINING_RW_OFFSET_OB_MISC ebc +EMC_TRAINING_OPT_CA_VREF ec0 +EMC_TRAINING_OPT_DQ_OB_VREF ec4 +EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 ec8 +EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 ecc +EMC_TRAINING_QUSE_VREF_CTRL ed0 +EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 ed4 +EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 ed8 +EMC_TRAINING_DRAMC_TIMING edc +EMC_PMACRO_QUSE_DDLL_RANK0_0 600 +EMC_PMACRO_QUSE_DDLL_RANK0_1 604 +EMC_PMACRO_QUSE_DDLL_RANK0_2 608 +EMC_PMACRO_QUSE_DDLL_RANK0_3 60c +EMC_PMACRO_QUSE_DDLL_RANK0_4 610 +EMC_PMACRO_QUSE_DDLL_RANK0_5 614 +EMC_PMACRO_QUSE_DDLL_RANK1_0 620 +EMC_PMACRO_QUSE_DDLL_RANK1_1 624 +EMC_PMACRO_QUSE_DDLL_RANK1_2 628 +EMC_PMACRO_QUSE_DDLL_RANK1_3 62c +EMC_PMACRO_QUSE_DDLL_RANK1_4 630 +EMC_PMACRO_QUSE_DDLL_RANK1_5 634 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 640 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 644 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 648 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 64c +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 650 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 654 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 660 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 664 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 668 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 66c +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 670 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 674 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 680 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 684 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 688 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 68c +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 690 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 694 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 6a0 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 6a4 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 6a8 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 6ac +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 6b0 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 6b4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 6c0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 6c4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 6c8 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 6cc +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 6d0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 6d4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 6e0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 6e4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 6e8 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 6ec +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 6f0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 6f4 +EMC_PMACRO_TX_PWRD_0 720 +EMC_PMACRO_TX_PWRD_1 724 +EMC_PMACRO_TX_PWRD_2 728 +EMC_PMACRO_TX_PWRD_3 72c +EMC_PMACRO_TX_PWRD_4 730 +EMC_PMACRO_TX_PWRD_5 734 +EMC_PMACRO_TX_SEL_CLK_SRC_0 740 +EMC_PMACRO_TX_SEL_CLK_SRC_1 744 +EMC_PMACRO_TX_SEL_CLK_SRC_3 74c +EMC_PMACRO_TX_SEL_CLK_SRC_2 748 +EMC_PMACRO_TX_SEL_CLK_SRC_4 750 +EMC_PMACRO_TX_SEL_CLK_SRC_5 754 +EMC_PMACRO_DDLL_BYPASS 760 +EMC_PMACRO_DDLL_PWRD_0 770 +EMC_PMACRO_DDLL_PWRD_1 774 +EMC_PMACRO_DDLL_PWRD_2 778 +EMC_PMACRO_CMD_CTRL_0 780 +EMC_PMACRO_CMD_CTRL_1 784 +EMC_PMACRO_CMD_CTRL_2 788 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 800 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 804 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 808 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 80c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 810 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 814 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 818 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 81c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 820 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 824 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 828 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 82c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 830 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 834 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 838 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 83c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 840 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 844 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 848 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 84c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 850 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 854 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 858 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 85c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 860 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 864 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 868 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 86c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 870 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 874 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 878 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 87c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 880 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 884 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 888 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 88c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 890 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 894 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 898 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 89c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 8a0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 8a4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 8a8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 8ac +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 8b0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 8b4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 8b8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 8bc +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 900 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 904 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 908 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 90c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 910 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 914 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 918 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 91c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 920 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 924 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 928 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 92c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 930 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 934 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 938 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 93c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 940 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 944 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 948 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 94c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 950 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 954 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 958 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 95c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 960 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 964 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 968 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 96c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 970 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 974 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 978 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 97c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 980 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 984 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 988 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 98c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 990 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 994 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 998 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 99c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 9a0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 9a4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 9a8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 9ac +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 9b0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 9b4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 9b8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 9bc +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 a00 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 a04 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 a08 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 a10 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 a14 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 a18 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 a20 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 a24 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 a28 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 a30 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 a34 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 a38 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 a40 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 a44 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 a48 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 a50 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 a54 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 a58 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 a60 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 a64 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 a68 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 a70 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 a74 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 a78 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 a80 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 a84 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 a88 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 a90 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 a94 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 a98 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 aa0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 aa4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 aa8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 ab0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 ab4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 ab8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 b00 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 b04 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 b08 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 b10 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 b14 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 b18 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 b20 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 b24 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 b28 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 b30 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 b34 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 b38 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 b40 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 b44 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 b48 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 b50 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 b54 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 b58 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 b60 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 b64 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 b68 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 b70 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 b74 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 b78 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 b80 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 b84 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 b88 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 b90 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 b94 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 b98 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 ba0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 ba4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 ba8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 bb0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 bb4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 bb8 +EMC_PMACRO_IB_VREF_DQ_0 be0 +EMC_PMACRO_IB_VREF_DQ_1 be4 +EMC_PMACRO_IB_VREF_DQ_2 be8 +EMC_PMACRO_IB_VREF_DQS_0 bf0 +EMC_PMACRO_IB_VREF_DQS_1 bf4 +EMC_PMACRO_IB_VREF_DQS_2 bf8 +EMC_PMACRO_IB_RXRT cf4 +EMC_PMACRO_DDLL_LONG_CMD_0 c00 +EMC_PMACRO_DDLL_LONG_CMD_1 c04 +EMC_PMACRO_DDLL_LONG_CMD_2 c08 +EMC_PMACRO_DDLL_LONG_CMD_3 c0c +EMC_PMACRO_DDLL_LONG_CMD_4 c10 +EMC_PMACRO_DDLL_LONG_CMD_5 c14 +EMC_PMACRO_DDLL_SHORT_CMD_0 c20 +EMC_PMACRO_DDLL_SHORT_CMD_1 c24 +EMC_PMACRO_DDLL_SHORT_CMD_2 c28 +EMC_PMACRO_CFG_PM_GLOBAL_0 c30 +EMC_PMACRO_VTTGEN_CTRL_0 c34 +EMC_PMACRO_VTTGEN_CTRL_1 c38 +EMC_PMACRO_VTTGEN_CTRL_2 cf0 +EMC_PMACRO_BG_BIAS_CTRL_0 c3c +EMC_PMACRO_PAD_CFG_CTRL c40 +EMC_PMACRO_CMD_PAD_RX_CTRL c50 +EMC_PMACRO_DATA_PAD_RX_CTRL c54 +EMC_PMACRO_CMD_RX_TERM_MODE c58 +EMC_PMACRO_DATA_RX_TERM_MODE c5c +EMC_PMACRO_CMD_PAD_TX_CTRL c60 +EMC_PMACRO_DATA_PAD_TX_CTRL c64 +EMC_PMACRO_COMMON_PAD_TX_CTRL c68 +EMC_PMACRO_BRICK_MAPPING_0 c80 +EMC_PMACRO_BRICK_MAPPING_1 c84 +EMC_PMACRO_BRICK_MAPPING_2 c88 +EMC_PMACRO_DDLLCAL_CAL ce0 +EMC_PMACRO_DDLL_OFFSET ce4 +EMC_PMACRO_DDLL_PERIODIC_OFFSET ce8 +EMC_PMACRO_BRICK_CTRL_RFU1 330 +EMC_PMACRO_BRICK_CTRL_RFU2 334 +EMC_PMACRO_CMD_BRICK_CTRL_FDPD 318 +EMC_PMACRO_DATA_BRICK_CTRL_FDPD 31c +EMC_PMACRO_TRAINING_CTRL_0 cf8 +EMC_PMACRO_TRAINING_CTRL_1 cfc +EMC_PMC_SCRATCH1 440 +EMC_PMC_SCRATCH2 444 +EMC_PMC_SCRATCH3 448 diff --git a/tools/fix_regs.py b/tools/fix_regs.py new file mode 100644 index 0000000..954a287 --- /dev/null +++ b/tools/fix_regs.py @@ -0,0 +1,36 @@ +import re +import sys + +def parse_defs(fname): + f = open(fname, "r") + lines = f.readlines() + f.close() + res = {} + for l in lines: + p = [str(_.strip()) for _ in l.strip().split(" ", 1)] + res[int(p[1], 16)] = p[0] + return res + +mc = parse_defs("mc.def") +emc = parse_defs("emc.def") + +f = open(sys.argv[1], "r") +buf = f.read() +f.close() + +def fix(m): + what = m.groups()[0] + off = int(m.groups()[1], 16) + if what == "MC": + if off in mc: + return "MC({0})".format(mc[off]) + elif what == "EMC": + if off in emc: + return "EMC({0})".format(emc[off]) + return "{0}(0x{1:X})".format(what, off) + +buf = re.sub(r'([A-Z]+)\(0x([0-9a-fA-F]+)\)', fix, buf) + +f = open(sys.argv[2], "w") +f.write(buf) +f.close() diff --git a/tools/lz/Makefile b/tools/lz/Makefile new file mode 100644 index 0000000..3d6fec8 --- /dev/null +++ b/tools/lz/Makefile @@ -0,0 +1,16 @@ +NATIVE_CC ?= gcc + +ifeq (, $(shell which $(NATIVE_CC) 2>/dev/null)) +$(error "Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=") +endif + +.PHONY: all clean + +all: lz77 + @echo > /dev/null + +clean: + @rm -f lz77 + +lz77: lz.c lz77.c + @$(NATIVE_CC) -o $@ lz.c lz77.c diff --git a/tools/lz/lz.c b/tools/lz/lz.c new file mode 100644 index 0000000..01a3e69 --- /dev/null +++ b/tools/lz/lz.c @@ -0,0 +1,546 @@ +// +// Name: lz.c +// Author: Marcus Geelnard +// Description: LZ77 coder/decoder implementation. +// Reentrant: Yes +// $ATH_LICENSE_NULL$ +// +// The LZ77 compression scheme is a substitutional compression scheme +// proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in +// its design, and uses no fancy bit level compression. +// +// This is my first attempt at an implementation of a LZ77 code/decoder. +// +// The principle of the LZ77 compression algorithm is to store repeated +// occurrences of strings as references to previous occurrences of the same +// string. The point is that the reference consumes less space than the +// string itself, provided that the string is long enough (in this +// implementation, the string has to be at least 4 bytes long, since the +// minimum coded reference is 3 bytes long). Also note that the term +// "string" refers to any kind of byte sequence (it does not have to be +// an ASCII string, for instance). +// +// The coder uses a brute force approach to finding string matches in the +// history buffer (or "sliding window", if you wish), which is very, very +// slow. I recon the complexity is somewhere between O(n^2) and O(n^3), +// depending on the input data. +// +// There is also a faster implementation that uses a large working buffer +// in which a "jump table" is stored, which is used to quickly find +// possible string matches (see the source code for LZ_CompressFast() for +// more information). The faster method is an order of magnitude faster, +// but still quite slow compared to other compression methods. +// +// The upside is that decompression is very fast, and the compression ratio +// is often very good. +// +// The reference to a string is coded as a (length,offset) pair, where the +// length indicates the length of the string, and the offset gives the +// offset from the current data position. To distinguish between string +// references and literal strings (uncompressed bytes), a string reference +// is preceded by a marker byte, which is chosen as the least common byte +// symbol in the input data stream (this marker byte is stored in the +// output stream as the first byte). +// +// Occurrences of the marker byte in the stream are encoded as the marker +// byte followed by a zero byte, which means that occurrences of the marker +// byte have to be coded with two bytes. +// +// The lengths and offsets are coded in a variable length fashion, allowing +// values of any magnitude (up to 4294967295 in this implementation). +// +// With this compression scheme, the worst case compression result is +// (257/256)*insize + 1. +// +//------------------------------------------------------------------------ +// Copyright (c) 2003-2006 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +// Marcus Geelnard +// marcus.geelnard at home.se +// + +// +// This file has been altered from the original version. +// + +/************************************************************************* +* Constants used for LZ77 coding +*************************************************************************/ + +/* Maximum offset (can be any size < 2^31). Lower values give faster + compression, while higher values gives better compression. The default + value of 100000 is quite high. Experiment to see what works best for + you. */ +#define LZ_MAX_OFFSET 100000 + + + +/************************************************************************* +* INTERNAL FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* _LZ_StringCompare() - Return maximum length string match. +*************************************************************************/ + +static unsigned int _LZ_StringCompare( unsigned char * str1, + unsigned char * str2, unsigned int minlen, unsigned int maxlen ) +{ + unsigned int len; + + for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len ); + + return len; +} + + +/************************************************************************* +* _LZ_WriteVarSize() - Write unsigned integer with variable number of +* bytes depending on value. +*************************************************************************/ + +static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf ) +{ + unsigned int y; + int num_bytes, i, b; + + /* Determine number of bytes needed to store the number x */ + y = x >> 3; + for( num_bytes = 5; num_bytes >= 2; -- num_bytes ) + { + if( y & 0xfe000000 ) break; + y <<= 7; + } + + /* Write all bytes, seven bits in each, with 8:th bit set for all */ + /* but the last byte. */ + for( i = num_bytes-1; i >= 0; -- i ) + { + b = (x >> (i*7)) & 0x0000007f; + if( i > 0 ) + { + b |= 0x00000080; + } + *buf ++ = (unsigned char) b; + } + + /* Return number of bytes written */ + return num_bytes; +} + + +/************************************************************************* +* _LZ_ReadVarSize() - Read unsigned integer with variable number of +* bytes depending on value. +*************************************************************************/ + +static int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf ) +{ + unsigned int y, b, num_bytes; + + /* Read complete value (stop when byte contains zero in 8:th bit) */ + y = 0; + num_bytes = 0; + do + { + b = (unsigned int) (*buf ++); + y = (y << 7) | (b & 0x0000007f); + ++ num_bytes; + } + while( b & 0x00000080 ); + + /* Store value in x */ + *x = y; + + /* Return number of bytes read */ + return num_bytes; +} + + + +/************************************************************************* +* PUBLIC FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* LZ_Compress() - Compress a block of data using an LZ77 coder. +* in - Input (uncompressed) buffer. +* out - Output (compressed) buffer. This buffer must be 0.4% larger +* than the input buffer, plus one byte. +* insize - Number of input bytes. +* The function returns the size of the compressed data. +*************************************************************************/ + +int LZ_Compress( unsigned char *in, unsigned char *out, + unsigned int insize ) +{ + unsigned char marker, symbol; + unsigned int inpos, outpos, bytesleft, i; + unsigned int maxoffset, offset, bestoffset; + unsigned int maxlength, length, bestlength; + unsigned int histogram[ 256 ]; + unsigned char *ptr1, *ptr2; + + /* Do we have anything to compress? */ + if( insize < 1 ) + { + return 0; + } + + /* Create histogram */ + for( i = 0; i < 256; ++ i ) + { + histogram[ i ] = 0; + } + for( i = 0; i < insize; ++ i ) + { + ++ histogram[ in[ i ] ]; + } + + /* Find the least common byte, and use it as the marker symbol */ + marker = 0; + for( i = 1; i < 256; ++ i ) + { + if( histogram[ i ] < histogram[ marker ] ) + { + marker = i; + } + } + + /* Remember the marker symbol for the decoder */ + out[ 0 ] = marker; + + /* Start of compression */ + inpos = 0; + outpos = 1; + + /* Main compression loop */ + bytesleft = insize; + do + { + /* Determine most distant position */ + if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET; + else maxoffset = inpos; + + /* Get pointer to current position */ + ptr1 = &in[ inpos ]; + + /* Search history window for maximum length string match */ + bestlength = 3; + bestoffset = 0; + for( offset = 3; offset <= maxoffset; ++ offset ) + { + /* Get pointer to candidate string */ + ptr2 = &ptr1[ -(int)offset ]; + + /* Quickly determine if this is a candidate (for speed) */ + if( (ptr1[ 0 ] == ptr2[ 0 ]) && + (ptr1[ bestlength ] == ptr2[ bestlength ]) ) + { + /* Determine maximum length for this offset */ + maxlength = (bytesleft < offset ? bytesleft : offset); + + /* Count maximum length match at this offset */ + length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength ); + + /* Better match than any previous match? */ + if( length > bestlength ) + { + bestlength = length; + bestoffset = offset; + } + } + } + + /* Was there a good enough match? */ + if( (bestlength >= 8) || + ((bestlength == 4) && (bestoffset <= 0x0000007f)) || + ((bestlength == 5) && (bestoffset <= 0x00003fff)) || + ((bestlength == 6) && (bestoffset <= 0x001fffff)) || + ((bestlength == 7) && (bestoffset <= 0x0fffffff)) ) + { + out[ outpos ++ ] = (unsigned char) marker; + outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] ); + outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] ); + inpos += bestlength; + bytesleft -= bestlength; + } + else + { + /* Output single byte (or two bytes if marker byte) */ + symbol = in[ inpos ++ ]; + out[ outpos ++ ] = symbol; + if( symbol == marker ) + { + out[ outpos ++ ] = 0; + } + -- bytesleft; + } + } + while( bytesleft > 3 ); + + /* Dump remaining bytes, if any */ + while( inpos < insize ) + { + if( in[ inpos ] == marker ) + { + out[ outpos ++ ] = marker; + out[ outpos ++ ] = 0; + } + else + { + out[ outpos ++ ] = in[ inpos ]; + } + ++ inpos; + } + + return outpos; +} + + +/************************************************************************* +* LZ_CompressFast() - Compress a block of data using an LZ77 coder. +* in - Input (uncompressed) buffer. +* out - Output (compressed) buffer. This buffer must be 0.4% larger +* than the input buffer, plus one byte. +* insize - Number of input bytes. +* work - Pointer to a temporary buffer (internal working buffer), which +* must be able to hold (insize+65536) unsigned integers. +* The function returns the size of the compressed data. +*************************************************************************/ + +int LZ_CompressFast( unsigned char *in, unsigned char *out, + unsigned int insize, unsigned int *work ) +{ + unsigned char marker, symbol; + unsigned int inpos, outpos, bytesleft, i, index, symbols; + unsigned int offset, bestoffset; + unsigned int maxlength, length, bestlength; + unsigned int histogram[ 256 ], *lastindex, *jumptable; + unsigned char *ptr1, *ptr2; + + /* Do we have anything to compress? */ + if( insize < 1 ) + { + return 0; + } + + /* Assign arrays to the working area */ + lastindex = work; + jumptable = &work[ 65536 ]; + + /* Build a "jump table". Here is how the jump table works: + jumptable[i] points to the nearest previous occurrence of the same + symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and + in[i+1] == in[jumptable[i]+1], and so on... Following the jump table + gives a dramatic boost for the string search'n'match loop compared + to doing a brute force search. The jump table is built in O(n) time, + so it is a cheap operation in terms of time, but it is expensice in + terms of memory consumption. */ + for( i = 0; i < 65536; ++ i ) + { + lastindex[ i ] = 0xffffffff; + } + for( i = 0; i < insize-1; ++ i ) + { + symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]); + index = lastindex[ symbols ]; + lastindex[ symbols ] = i; + jumptable[ i ] = index; + } + jumptable[ insize-1 ] = 0xffffffff; + + /* Create histogram */ + for( i = 0; i < 256; ++ i ) + { + histogram[ i ] = 0; + } + for( i = 0; i < insize; ++ i ) + { + ++ histogram[ in[ i ] ]; + } + + /* Find the least common byte, and use it as the marker symbol */ + marker = 0; + for( i = 1; i < 256; ++ i ) + { + if( histogram[ i ] < histogram[ marker ] ) + { + marker = i; + } + } + + /* Remember the marker symbol for the decoder */ + out[ 0 ] = marker; + + /* Start of compression */ + inpos = 0; + outpos = 1; + + /* Main compression loop */ + bytesleft = insize; + do + { + /* Get pointer to current position */ + ptr1 = &in[ inpos ]; + + /* Search history window for maximum length string match */ + bestlength = 3; + bestoffset = 0; + index = jumptable[ inpos ]; + while( (index != 0xffffffff) && ((inpos - index) < LZ_MAX_OFFSET) ) + { + /* Get pointer to candidate string */ + ptr2 = &in[ index ]; + + /* Quickly determine if this is a candidate (for speed) */ + if( ptr2[ bestlength ] == ptr1[ bestlength ] ) + { + /* Determine maximum length for this offset */ + offset = inpos - index; + maxlength = (bytesleft < offset ? bytesleft : offset); + + /* Count maximum length match at this offset */ + length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength ); + + /* Better match than any previous match? */ + if( length > bestlength ) + { + bestlength = length; + bestoffset = offset; + } + } + + /* Get next possible index from jump table */ + index = jumptable[ index ]; + } + + /* Was there a good enough match? */ + if( (bestlength >= 8) || + ((bestlength == 4) && (bestoffset <= 0x0000007f)) || + ((bestlength == 5) && (bestoffset <= 0x00003fff)) || + ((bestlength == 6) && (bestoffset <= 0x001fffff)) || + ((bestlength == 7) && (bestoffset <= 0x0fffffff)) ) + { + out[ outpos ++ ] = (unsigned char) marker; + outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] ); + outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] ); + inpos += bestlength; + bytesleft -= bestlength; + } + else + { + /* Output single byte (or two bytes if marker byte) */ + symbol = in[ inpos ++ ]; + out[ outpos ++ ] = symbol; + if( symbol == marker ) + { + out[ outpos ++ ] = 0; + } + -- bytesleft; + } + } + while( bytesleft > 3 ); + + /* Dump remaining bytes, if any */ + while( inpos < insize ) + { + if( in[ inpos ] == marker ) + { + out[ outpos ++ ] = marker; + out[ outpos ++ ] = 0; + } + else + { + out[ outpos ++ ] = in[ inpos ]; + } + ++ inpos; + } + + return outpos; +} + + +/************************************************************************* +* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder. +* in - Input (compressed) buffer. +* out - Output (uncompressed) buffer. This buffer must be large +* enough to hold the uncompressed data. +* insize - Number of input bytes. +*************************************************************************/ + +int LZ_Uncompress( unsigned char *in, unsigned char *out, + unsigned int insize ) +{ + unsigned char marker, symbol; + unsigned int i, inpos, outpos, length, offset; + + /* Do we have anything to uncompress? */ + if( insize < 1 ) + { + return 0; + } + + /* Get marker symbol from input stream */ + marker = in[ 0 ]; + inpos = 1; + + /* Main decompression loop */ + outpos = 0; + do + { + symbol = in[ inpos ++ ]; + if( symbol == marker ) + { + /* We had a marker byte */ + if( in[ inpos ] == 0 ) + { + /* It was a single occurrence of the marker byte */ + out[ outpos ++ ] = marker; + ++ inpos; + } + else + { + /* Extract true length and offset */ + inpos += _LZ_ReadVarSize( &length, &in[ inpos ] ); + inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] ); + + /* Copy corresponding data from history window */ + for( i = 0; i < length; ++ i ) + { + out[ outpos ] = out[ outpos - offset ]; + ++ outpos; + } + } + } + else + { + /* No marker, plain copy */ + out[ outpos ++ ] = symbol; + } + } + while( inpos < insize ); + + return outpos; +} diff --git a/tools/lz/lz.h b/tools/lz/lz.h new file mode 100644 index 0000000..7f7b22a --- /dev/null +++ b/tools/lz/lz.h @@ -0,0 +1,61 @@ +// +// Name: lz.h +// Author: Marcus Geelnard +// Description: LZ77 coder/decoder interface. +// Reentrant: Yes +// ------------------------------------------------------------------------ +// $ATH_LICENSE_NULL$ +// Copyright (c) 2003-2006 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +// Marcus Geelnard +// marcus.geelnard at home.se +// + +// +// This file has been altered from the original version. +// + +#ifndef _lz_h_ +#define _lz_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* +* Function prototypes +*************************************************************************/ + +int LZ_Compress( unsigned char *in, unsigned char *out, + unsigned int insize ); +int LZ_CompressFast( unsigned char *in, unsigned char *out, + unsigned int insize, unsigned int *work ); +int LZ_Uncompress( unsigned char *in, unsigned char *out, + unsigned int insize ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _lz_h_ */ diff --git a/tools/lz/lz77.c b/tools/lz/lz77.c new file mode 100644 index 0000000..75b90a6 --- /dev/null +++ b/tools/lz/lz77.c @@ -0,0 +1,93 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include "lz.h" + +char filename[1024]; + +int main(int argc, char *argv[]) +{ + int nbytes; + int filename_len; + struct stat statbuf; + FILE *in_file, *out_file; + + if(stat(argv[1], &statbuf)) + goto error; + + if((in_file=fopen(argv[1], "rb")) == NULL) + goto error; + + strcpy(filename, argv[1]); + filename_len = strlen(filename); + + uint32_t in_size = statbuf.st_size; + uint8_t *in_buf = (uint8_t *)malloc(in_size); + + uint32_t out_size = statbuf.st_size + 257; + uint8_t *out_buf = (uint8_t *)malloc(out_size); + + if(!(in_buf && out_buf)) + goto error; + + if(fread(in_buf, 1, in_size, in_file) != in_size) + goto error; + + fclose(in_file); + + uint32_t *work = (uint32_t*)malloc(sizeof(uint32_t) * (in_size + 65536)); + for (int i = 0; i < 2; i++) + { + uint32_t in_size_tmp; + if (!i) + { + in_size_tmp = in_size / 2; + strcpy(filename + filename_len, ".00.lz"); + } + else + { + in_size_tmp = in_size - (in_size / 2); + strcpy(filename + filename_len, ".01.lz"); + } + + if (work) + nbytes = LZ_CompressFast(in_buf + (in_size / 2) * i, out_buf, in_size_tmp, work); + else + goto error; + + if (nbytes > out_size) + goto error; + + if((out_file = fopen(filename,"wb")) == NULL) + goto error; + + if (fwrite(out_buf, 1, nbytes, out_file) != nbytes) + goto error; + + fclose(out_file); + } + + return 0; + +error: + fprintf(stderr, "Failed to compress: %s\n", argv[1]); + exit(1); +} diff --git a/tools/mc.def b/tools/mc.def new file mode 100644 index 0000000..62f3835 --- /dev/null +++ b/tools/mc.def @@ -0,0 +1,448 @@ +MC_INTSTATUS 0 +MC_INTMASK 4 +MC_ERR_STATUS 8 +MC_ERR_ADR c +MC_PCFIFO_CLIENT_CONFIG0 dd0 +MC_PCFIFO_CLIENT_CONFIG1 dd4 +MC_PCFIFO_CLIENT_CONFIG2 dd8 +MC_PCFIFO_CLIENT_CONFIG3 ddc +MC_PCFIFO_CLIENT_CONFIG4 de0 +MC_EMEM_CFG 50 +MC_EMEM_ADR_CFG 54 +MC_EMEM_ADR_CFG_DEV0 58 +MC_EMEM_ADR_CFG_DEV1 5c +MC_EMEM_ADR_CFG_CHANNEL_MASK 60 +MC_EMEM_ADR_CFG_BANK_MASK_0 64 +MC_EMEM_ADR_CFG_BANK_MASK_1 68 +MC_EMEM_ADR_CFG_BANK_MASK_2 6c +MC_SECURITY_CFG0 70 +MC_SECURITY_CFG1 74 +MC_SECURITY_CFG3 9bc +MC_SECURITY_RSV 7c +MC_EMEM_ARB_CFG 90 +MC_EMEM_ARB_OUTSTANDING_REQ 94 +MC_EMEM_ARB_TIMING_RCD 98 +MC_EMEM_ARB_TIMING_RP 9c +MC_EMEM_ARB_TIMING_RC a0 +MC_EMEM_ARB_TIMING_RAS a4 +MC_EMEM_ARB_TIMING_FAW a8 +MC_EMEM_ARB_TIMING_RRD ac +MC_EMEM_ARB_TIMING_RAP2PRE b0 +MC_EMEM_ARB_TIMING_WAP2PRE b4 +MC_EMEM_ARB_TIMING_R2R b8 +MC_EMEM_ARB_TIMING_W2W bc +MC_EMEM_ARB_TIMING_R2W c0 +MC_EMEM_ARB_TIMING_W2R c4 +MC_EMEM_ARB_TIMING_RFCPB 6c0 +MC_EMEM_ARB_TIMING_CCDMW 6c4 +MC_EMEM_ARB_REFPB_HP_CTRL 6f0 +MC_EMEM_ARB_REFPB_BANK_CTRL 6f4 +MC_EMEM_ARB_DA_TURNS d0 +MC_EMEM_ARB_DA_COVERS d4 +MC_EMEM_ARB_MISC0 d8 +MC_EMEM_ARB_MISC1 dc +MC_EMEM_ARB_MISC2 c8 +MC_EMEM_ARB_RING1_THROTTLE e0 +MC_EMEM_ARB_RING3_THROTTLE e4 +MC_EMEM_ARB_NISO_THROTTLE 6b0 +MC_EMEM_ARB_OVERRIDE e8 +MC_EMEM_ARB_RSV ec +MC_CLKEN_OVERRIDE f4 +MC_TIMING_CONTROL_DBG f8 +MC_TIMING_CONTROL fc +MC_STAT_CONTROL 100 +MC_STAT_STATUS 104 +MC_STAT_EMC_CLOCK_LIMIT 108 +MC_STAT_EMC_CLOCK_LIMIT_MSBS 10c +MC_STAT_EMC_CLOCKS 110 +MC_STAT_EMC_CLOCKS_MSBS 114 +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 118 +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 158 +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 11c +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 15c +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER a20 +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER a24 +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 198 +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 1a8 +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 19c +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 1ac +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER a28 +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER a2c +MC_STAT_EMC_FILTER_SET0_ASID 1a0 +MC_STAT_EMC_FILTER_SET1_ASID 1b0 +MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 120 +MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 160 +MC_STAT_EMC_FILTER_SET0_CLIENT_0 128 +MC_STAT_EMC_FILTER_SET1_CLIENT_0 168 +MC_STAT_EMC_FILTER_SET0_CLIENT_1 12c +MC_STAT_EMC_FILTER_SET1_CLIENT_1 16c +MC_STAT_EMC_FILTER_SET0_CLIENT_2 130 +MC_STAT_EMC_FILTER_SET1_CLIENT_2 170 +MC_STAT_EMC_FILTER_SET0_CLIENT_3 134 +MC_STAT_EMC_FILTER_SET0_CLIENT_4 b88 +MC_STAT_EMC_FILTER_SET1_CLIENT_3 174 +MC_STAT_EMC_FILTER_SET1_CLIENT_4 b8c +MC_STAT_EMC_SET0_COUNT 138 +MC_STAT_EMC_SET0_COUNT_MSBS 13c +MC_STAT_EMC_SET1_COUNT 178 +MC_STAT_EMC_SET1_COUNT_MSBS 17c +MC_STAT_EMC_SET0_SLACK_ACCUM 140 +MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 144 +MC_STAT_EMC_SET1_SLACK_ACCUM 180 +MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 184 +MC_STAT_EMC_SET0_HISTO_COUNT 148 +MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 14c +MC_STAT_EMC_SET1_HISTO_COUNT 188 +MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 18c +MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 150 +MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 190 +MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 1b8 +MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 1bc +MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 1c8 +MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 1cc +MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 1c0 +MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 1d0 +MC_CLIENT_HOTRESET_CTRL 200 +MC_CLIENT_HOTRESET_CTRL_1 970 +MC_CLIENT_HOTRESET_STATUS 204 +MC_CLIENT_HOTRESET_STATUS_1 974 +MC_EMEM_ARB_ISOCHRONOUS_0 208 +MC_EMEM_ARB_ISOCHRONOUS_1 20c +MC_EMEM_ARB_ISOCHRONOUS_2 210 +MC_EMEM_ARB_ISOCHRONOUS_3 214 +MC_EMEM_ARB_ISOCHRONOUS_4 b94 +MC_EMEM_ARB_HYSTERESIS_0 218 +MC_EMEM_ARB_HYSTERESIS_1 21c +MC_EMEM_ARB_HYSTERESIS_2 220 +MC_EMEM_ARB_HYSTERESIS_3 224 +MC_EMEM_ARB_HYSTERESIS_4 b84 +MC_EMEM_ARB_DHYSTERESIS_0 bb0 +MC_EMEM_ARB_DHYSTERESIS_1 bb4 +MC_EMEM_ARB_DHYSTERESIS_2 bb8 +MC_EMEM_ARB_DHYSTERESIS_3 bbc +MC_EMEM_ARB_DHYSTERESIS_4 bc0 +MC_EMEM_ARB_DHYST_CTRL bcc +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 bd0 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 bd4 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 bd8 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 bdc +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 be0 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 be4 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 be8 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 bec +MC_RESERVED_RSV 3fc +MC_DISB_EXTRA_SNAP_LEVELS 408 +MC_APB_EXTRA_SNAP_LEVELS 2a4 +MC_AHB_EXTRA_SNAP_LEVELS 2a0 +MC_USBD_EXTRA_SNAP_LEVELS a18 +MC_ISP_EXTRA_SNAP_LEVELS a08 +MC_AUD_EXTRA_SNAP_LEVELS a10 +MC_MSE_EXTRA_SNAP_LEVELS 40c +MC_GK2_EXTRA_SNAP_LEVELS a40 +MC_A9AVPPC_EXTRA_SNAP_LEVELS 414 +MC_FTOP_EXTRA_SNAP_LEVELS 2bc +MC_JPG_EXTRA_SNAP_LEVELS a3c +MC_HOST_EXTRA_SNAP_LEVELS a14 +MC_SAX_EXTRA_SNAP_LEVELS 2c0 +MC_DIS_EXTRA_SNAP_LEVELS 2ac +MC_VICPC_EXTRA_SNAP_LEVELS a1c +MC_HDAPC_EXTRA_SNAP_LEVELS a48 +MC_AVP_EXTRA_SNAP_LEVELS 2a8 +MC_USBX_EXTRA_SNAP_LEVELS 404 +MC_PCX_EXTRA_SNAP_LEVELS 2b8 +MC_SD_EXTRA_SNAP_LEVELS a04 +MC_DFD_EXTRA_SNAP_LEVELS a4c +MC_VE_EXTRA_SNAP_LEVELS 2d8 +MC_GK_EXTRA_SNAP_LEVELS a00 +MC_VE2_EXTRA_SNAP_LEVELS 410 +MC_SDM_EXTRA_SNAP_LEVELS a44 +MC_VIDEO_PROTECT_BOM 648 +MC_VIDEO_PROTECT_SIZE_MB 64c +MC_VIDEO_PROTECT_BOM_ADR_HI 978 +MC_VIDEO_PROTECT_REG_CTRL 650 +MC_ERR_VPR_STATUS 654 +MC_ERR_VPR_ADR 658 +MC_VIDEO_PROTECT_VPR_OVERRIDE 418 +MC_VIDEO_PROTECT_VPR_OVERRIDE1 590 +MC_IRAM_BOM 65c +MC_IRAM_TOM 660 +MC_IRAM_ADR_HI 980 +MC_IRAM_REG_CTRL 964 +MC_EMEM_CFG_ACCESS_CTRL 664 +MC_TZ_SECURITY_CTRL 668 +MC_EMEM_ARB_OUTSTANDING_REQ_RING3 66c +MC_EMEM_ARB_OUTSTANDING_REQ_NISO 6b4 +MC_EMEM_ARB_RING0_THROTTLE_MASK 6bc +MC_EMEM_ARB_NISO_THROTTLE_MASK 6b8 +MC_EMEM_ARB_NISO_THROTTLE_MASK_1 b80 +MC_SEC_CARVEOUT_BOM 670 +MC_SEC_CARVEOUT_SIZE_MB 674 +MC_SEC_CARVEOUT_ADR_HI 9d4 +MC_SEC_CARVEOUT_REG_CTRL 678 +MC_ERR_SEC_STATUS 67c +MC_ERR_SEC_ADR 680 +MC_PC_IDLE_CLOCK_GATE_CONFIG 684 +MC_STUTTER_CONTROL 688 +MC_RESERVED_RSV_1 958 +MC_DVFS_PIPE_SELECT 95c +MC_AHB_PTSA_MIN 4e0 +MC_AUD_PTSA_MIN 54c +MC_MLL_MPCORER_PTSA_RATE 44c +MC_RING2_PTSA_RATE 440 +MC_USBD_PTSA_RATE 530 +MC_USBX_PTSA_MIN 528 +MC_USBD_PTSA_MIN 534 +MC_APB_PTSA_MAX 4f0 +MC_JPG_PTSA_RATE 584 +MC_DIS_PTSA_MIN 420 +MC_AVP_PTSA_MAX 4fc +MC_AVP_PTSA_RATE 4f4 +MC_RING1_PTSA_MIN 480 +MC_DIS_PTSA_MAX 424 +MC_SD_PTSA_MAX 4d8 +MC_MSE_PTSA_RATE 4c4 +MC_VICPC_PTSA_MIN 558 +MC_PCX_PTSA_MAX 4b4 +MC_ISP_PTSA_RATE 4a0 +MC_A9AVPPC_PTSA_MIN 48c +MC_RING2_PTSA_MAX 448 +MC_AUD_PTSA_RATE 548 +MC_HOST_PTSA_MIN 51c +MC_MLL_MPCORER_PTSA_MAX 454 +MC_SD_PTSA_MIN 4d4 +MC_RING1_PTSA_RATE 47c +MC_JPG_PTSA_MIN 588 +MC_HDAPC_PTSA_MIN 62c +MC_AVP_PTSA_MIN 4f8 +MC_JPG_PTSA_MAX 58c +MC_VE_PTSA_MAX 43c +MC_DFD_PTSA_MAX 63c +MC_VICPC_PTSA_RATE 554 +MC_GK_PTSA_MAX 544 +MC_VICPC_PTSA_MAX 55c +MC_SDM_PTSA_MAX 624 +MC_SAX_PTSA_RATE 4b8 +MC_PCX_PTSA_MIN 4b0 +MC_APB_PTSA_MIN 4ec +MC_GK2_PTSA_MIN 614 +MC_PCX_PTSA_RATE 4ac +MC_RING1_PTSA_MAX 484 +MC_HDAPC_PTSA_RATE 628 +MC_MLL_MPCORER_PTSA_MIN 450 +MC_GK2_PTSA_MAX 618 +MC_AUD_PTSA_MAX 550 +MC_GK2_PTSA_RATE 610 +MC_ISP_PTSA_MAX 4a8 +MC_DISB_PTSA_RATE 428 +MC_VE2_PTSA_MAX 49c +MC_DFD_PTSA_MIN 638 +MC_FTOP_PTSA_RATE 50c +MC_A9AVPPC_PTSA_RATE 488 +MC_VE2_PTSA_MIN 498 +MC_USBX_PTSA_MAX 52c +MC_DIS_PTSA_RATE 41c +MC_USBD_PTSA_MAX 538 +MC_A9AVPPC_PTSA_MAX 490 +MC_USBX_PTSA_RATE 524 +MC_FTOP_PTSA_MAX 514 +MC_HDAPC_PTSA_MAX 630 +MC_SD_PTSA_RATE 4d0 +MC_DFD_PTSA_RATE 634 +MC_FTOP_PTSA_MIN 510 +MC_SDM_PTSA_RATE 61c +MC_AHB_PTSA_RATE 4dc +MC_SMMU_SMMU_PTSA_MAX 460 +MC_RING2_PTSA_MIN 444 +MC_SDM_PTSA_MIN 620 +MC_APB_PTSA_RATE 4e8 +MC_MSE_PTSA_MIN 4c8 +MC_HOST_PTSA_RATE 518 +MC_VE_PTSA_RATE 434 +MC_AHB_PTSA_MAX 4e4 +MC_SAX_PTSA_MIN 4bc +MC_SMMU_SMMU_PTSA_MIN 45c +MC_ISP_PTSA_MIN 4a4 +MC_HOST_PTSA_MAX 520 +MC_SAX_PTSA_MAX 4c0 +MC_VE_PTSA_MIN 438 +MC_GK_PTSA_MIN 540 +MC_MSE_PTSA_MAX 4cc +MC_DISB_PTSA_MAX 430 +MC_DISB_PTSA_MIN 42c +MC_SMMU_SMMU_PTSA_RATE 458 +MC_VE2_PTSA_RATE 494 +MC_GK_PTSA_RATE 53c +MC_PTSA_GRANT_DECREMENT 960 +MC_LATENCY_ALLOWANCE_AVPC_0 2e4 +MC_LATENCY_ALLOWANCE_AXIAP_0 3a0 +MC_LATENCY_ALLOWANCE_XUSB_1 380 +MC_LATENCY_ALLOWANCE_ISP2B_0 384 +MC_LATENCY_ALLOWANCE_SDMMCAA_0 3bc +MC_LATENCY_ALLOWANCE_SDMMCA_0 3b8 +MC_LATENCY_ALLOWANCE_ISP2_0 370 +MC_LATENCY_ALLOWANCE_SE_0 3e0 +MC_LATENCY_ALLOWANCE_ISP2_1 374 +MC_LATENCY_ALLOWANCE_DC_0 2e8 +MC_LATENCY_ALLOWANCE_VIC_0 394 +MC_LATENCY_ALLOWANCE_DCB_1 2f8 +MC_LATENCY_ALLOWANCE_NVDEC_0 3d8 +MC_LATENCY_ALLOWANCE_DCB_2 2fc +MC_LATENCY_ALLOWANCE_TSEC_0 390 +MC_LATENCY_ALLOWANCE_DC_2 2f0 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 694 +MC_LATENCY_ALLOWANCE_PPCS_1 348 +MC_LATENCY_ALLOWANCE_XUSB_0 37c +MC_LATENCY_ALLOWANCE_PPCS_0 344 +MC_LATENCY_ALLOWANCE_TSECB_0 3f0 +MC_LATENCY_ALLOWANCE_AFI_0 2e0 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 698 +MC_LATENCY_ALLOWANCE_DC_1 2ec +MC_LATENCY_ALLOWANCE_APE_0 3dc +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 6a0 +MC_LATENCY_ALLOWANCE_A9AVP_0 3a4 +MC_LATENCY_ALLOWANCE_GPU2_0 3e8 +MC_LATENCY_ALLOWANCE_DCB_0 2f4 +MC_LATENCY_ALLOWANCE_HC_1 314 +MC_LATENCY_ALLOWANCE_SDMMC_0 3c0 +MC_LATENCY_ALLOWANCE_NVJPG_0 3e4 +MC_LATENCY_ALLOWANCE_PTC_0 34c +MC_LATENCY_ALLOWANCE_ETR_0 3ec +MC_LATENCY_ALLOWANCE_MPCORE_0 320 +MC_LATENCY_ALLOWANCE_VI2_0 398 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 69c +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 6a4 +MC_LATENCY_ALLOWANCE_SATA_0 350 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 690 +MC_LATENCY_ALLOWANCE_HC_0 310 +MC_LATENCY_ALLOWANCE_DC_3 3c8 +MC_LATENCY_ALLOWANCE_GPU_0 3ac +MC_LATENCY_ALLOWANCE_SDMMCAB_0 3c4 +MC_LATENCY_ALLOWANCE_ISP2B_1 388 +MC_LATENCY_ALLOWANCE_NVENC_0 328 +MC_LATENCY_ALLOWANCE_HDA_0 318 +MC_MIN_LENGTH_APE_0 b34 +MC_MIN_LENGTH_DCB_2 8a8 +MC_MIN_LENGTH_A9AVP_0 950 +MC_MIN_LENGTH_TSEC_0 93c +MC_MIN_LENGTH_DC_1 898 +MC_MIN_LENGTH_AXIAP_0 94c +MC_MIN_LENGTH_ISP2B_0 930 +MC_MIN_LENGTH_VI2_0 944 +MC_MIN_LENGTH_DCB_0 8a0 +MC_MIN_LENGTH_DCB_1 8a4 +MC_MIN_LENGTH_PPCS_1 8f4 +MC_MIN_LENGTH_NVJPG_0 b3c +MC_MIN_LENGTH_HDA_0 8c4 +MC_MIN_LENGTH_NVENC_0 8d4 +MC_MIN_LENGTH_SDMMC_0 b18 +MC_MIN_LENGTH_ISP2B_1 934 +MC_MIN_LENGTH_HC_1 8c0 +MC_MIN_LENGTH_DC_3 b20 +MC_MIN_LENGTH_AVPC_0 890 +MC_MIN_LENGTH_VIC_0 940 +MC_MIN_LENGTH_ISP2_0 91c +MC_MIN_LENGTH_HC_0 8bc +MC_MIN_LENGTH_SE_0 b38 +MC_MIN_LENGTH_NVDEC_0 b30 +MC_MIN_LENGTH_SATA_0 8fc +MC_MIN_LENGTH_DC_0 894 +MC_MIN_LENGTH_XUSB_1 92c +MC_MIN_LENGTH_DC_2 89c +MC_MIN_LENGTH_SDMMCAA_0 b14 +MC_MIN_LENGTH_GPU_0 b04 +MC_MIN_LENGTH_ETR_0 b44 +MC_MIN_LENGTH_AFI_0 88c +MC_MIN_LENGTH_PPCS_0 8f0 +MC_MIN_LENGTH_ISP2_1 920 +MC_MIN_LENGTH_XUSB_0 928 +MC_MIN_LENGTH_MPCORE_0 8cc +MC_MIN_LENGTH_TSECB_0 b48 +MC_MIN_LENGTH_SDMMCA_0 b10 +MC_MIN_LENGTH_GPU2_0 b40 +MC_MIN_LENGTH_SDMMCAB_0 b1c +MC_MIN_LENGTH_PTC_0 8f8 +MC_EMEM_ARB_OVERRIDE_1 968 +MC_VIDEO_PROTECT_GPU_OVERRIDE_0 984 +MC_VIDEO_PROTECT_GPU_OVERRIDE_1 988 +MC_EMEM_ARB_STATS_0 990 +MC_EMEM_ARB_STATS_1 994 +MC_MTS_CARVEOUT_BOM 9a0 +MC_MTS_CARVEOUT_SIZE_MB 9a4 +MC_MTS_CARVEOUT_ADR_HI 9a8 +MC_MTS_CARVEOUT_REG_CTRL 9ac +MC_ERR_MTS_STATUS 9b0 +MC_ERR_MTS_ADR 9b4 +MC_ERR_GENERALIZED_CARVEOUT_STATUS c00 +MC_ERR_GENERALIZED_CARVEOUT_ADR c04 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 d74 +MC_SECURITY_CARVEOUT4_CFG0 cf8 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 d10 +MC_SECURITY_CARVEOUT4_SIZE_128KB d04 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 c28 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 c30 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 c8c +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 d1c +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 d70 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 c2c +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 d7c +MC_SECURITY_CARVEOUT3_SIZE_128KB cb4 +MC_SECURITY_CARVEOUT2_CFG0 c58 +MC_SECURITY_CARVEOUT1_CFG0 c08 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 c84 +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 c68 +MC_SECURITY_CARVEOUT3_BOM cac +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 c70 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 d78 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 c7c +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 d18 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 cbc +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 c38 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 c34 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 cc0 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 d60 +MC_SECURITY_CARVEOUT3_CFG0 ca8 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 cb8 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 c88 +MC_SECURITY_CARVEOUT2_SIZE_128KB c64 +MC_SECURITY_CARVEOUT5_BOM_HI d50 +MC_SECURITY_CARVEOUT1_SIZE_128KB c14 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 d14 +MC_SECURITY_CARVEOUT1_BOM c0c +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 d2c +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 d68 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 cc8 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 d58 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 d24 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 cc4 +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 c78 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 c1c +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 c18 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 d28 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 d5c +MC_SECURITY_CARVEOUT3_BOM_HI cb0 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 cd8 +MC_SECURITY_CARVEOUT2_BOM_HI c60 +MC_SECURITY_CARVEOUT4_BOM_HI d00 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 d64 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 cdc +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 c80 +MC_SECURITY_CARVEOUT5_SIZE_128KB d54 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 d20 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 cd4 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 d0c +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 c74 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 ccc +MC_SECURITY_CARVEOUT4_BOM cfc +MC_SECURITY_CARVEOUT5_CFG0 d48 +MC_SECURITY_CARVEOUT2_BOM c5c +MC_SECURITY_CARVEOUT5_BOM d4c +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 c24 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 d6c +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 cd0 +MC_SECURITY_CARVEOUT1_BOM_HI c10 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 c20 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 c3c +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 c6c +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 d08 +MC_ERR_APB_ASID_UPDATE_STATUS 9d0 +MC_DA_CONFIG0 9dc diff --git a/tools/smmu_payload.py b/tools/smmu_payload.py new file mode 100644 index 0000000..8961b25 --- /dev/null +++ b/tools/smmu_payload.py @@ -0,0 +1,38 @@ +''' +Copyright (c) 2018 balika011 + +This program is free software; you can redistribute it and/or modify it +under the terms and conditions of the GNU General Public License, +version 2, as published by the Free Software Foundation. + +This program is distributed in the hope it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +''' + +from keystone import * + +CODE = b''' + LDR X1, =0x70019010 + MOV X0, #0x1 + STR W0, [X1] + +loop: + IC IALLUIS + DSB ISH + B loop + MOV X0, #0x0 + STR W0, [X1] + LDR X0, =0x4002B000 + BR X0 +''' +try: + ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN) + encoding, count = ks.asm(CODE, 0x0) + print("%s = %s (number of statements: %u)" %(CODE, ', '.join([('0x%02x' % (x)) for x in encoding]), count)) +except KsError as e: + print("ERROR: %s" %e) \ No newline at end of file From 92a23d905512b021cbeb37d01574764fca24db99 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 17:25:55 -0600 Subject: [PATCH 106/166] loader: Trim unneeded data --- loader/link.ld | 1 - loader/loader.c | 20 -------------------- 2 files changed, 21 deletions(-) diff --git a/loader/link.ld b/loader/link.ld index 1196fd4..cf5cb17 100644 --- a/loader/link.ld +++ b/loader/link.ld @@ -6,7 +6,6 @@ SECTIONS { .text : { *(.text._start); KEEP(*(._boot_cfg)); - KEEP(*(._octopus)); *(.text*); } .data : { diff --git a/loader/loader.c b/loader/loader.c index 5ec2060..11e6018 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -31,26 +31,6 @@ boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; -const volatile char __attribute__((section ("._octopus"))) octopus[] = - "\n" - " ___\n" - " .-' `'.\n" - " / \\\n" - " | ;\n" - " | | ___.--,\n" - " _.._ |0) = (0) | _.---'`__.-( (_.\n" - " __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n" - " ( ,.--'` ',__ /./; ;, '.__.'` __\n" - " _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n" - " `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n" - " | | .' _.-' | | \\ \\ '. `----`\n" - " \\ \\/ .' \\ \\ '. '-._)\n" - " \\/ / \\ \\ `=.__`'-.\n" - " / /\\ `) ) / / `\"\".`\\\n" - " , _.-'.'\\ \\ / / ( ( / /\n" - " `--'` ) ) .-'.' '.'. | (\n" - " (/` ( (` ) ) '-; [switchbrew]\n"; - void loader_main() { // Preliminary BPMP clocks init. From dd07af27df8a428c0c429e05013ad98c4ba65e9a Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 17:26:10 -0600 Subject: [PATCH 107/166] tui: Bring back status bar --- source/gfx/tui.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/gfx/tui.c b/source/gfx/tui.c index 173178a..6d0e6b4 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -86,7 +86,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) gfx_con_setpos(cx, cy); // Update status bar. - // tui_sbar(false); + tui_sbar(false); } void *tui_do_menu(menu_t *menu) @@ -94,7 +94,7 @@ void *tui_do_menu(menu_t *menu) int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF; gfx_clear_partial_grey(0x1B, 0, 1256); - // tui_sbar(true); + tui_sbar(true); while (true) { @@ -203,7 +203,7 @@ void *tui_do_menu(menu_t *menu) gfx_con.fntsz = 16; gfx_clear_partial_grey(0x1B, 0, 1256); } - // tui_sbar(false); + tui_sbar(false); } return NULL; From 433f989b4f4bf08c83ae117c2d29b4346eb45f20 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 12 May 2021 17:28:29 -0600 Subject: [PATCH 108/166] Bump version to v1.9.2 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 4f56f2c..e930c47 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,4 +1,4 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 1 +LPVERSION_BUGFX := 2 From 9110d8d405b2e34c514deae14fe0e0759d0f478e Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Jul 2021 11:14:55 -0600 Subject: [PATCH 109/166] 12.1.0 and agnostic support until next key change --- bdk/sec/se.c | 2 +- bdk/utils/types.h | 2 ++ source/hos/pkg1.c | 53 ++++++++++++++++++++++++------------- source/keys/key_sources.inl | 36 ++++++++++++++----------- 4 files changed, 57 insertions(+), 36 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 92767b9..706e83d 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -391,7 +391,7 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_CNTN(1); _se_aes_ctr_set(ctr); - u32 src_size_aligned = src_size & 0xFFFFFFF0; + u32 src_size_aligned = ALIGN_DOWN(src_size, 0x10); u32 src_size_delta = src_size & 0xF; if (src_size_aligned) diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 9e8e716..afa6853 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -30,6 +30,8 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) #define LOG2(n) (32 - __builtin_clz(n) - 1) +#define CLZ(n) __builtin_clz(n) +#define CLO(n) __builtin_clz(~n) #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 4800aff..1f2942a 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -20,27 +20,30 @@ #include #include "pkg1.h" +#include "hos.h" +#include #include static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0 }, //1.0.0 - { "20170210155124", 0 }, //2.0.0 - 2.3.0 - { "20170519101410", 1 }, //3.0.0 - { "20170710161758", 2 }, //3.0.1 - 3.0.2 - { "20170921172629", 3 }, //4.0.0 - 4.1.0 - { "20180220163747", 4 }, //5.0.0 - 5.1.0 - { "20180802162753", 5 }, //6.0.0 - 6.1.0 - { "20181107105733", 6 }, //6.2.0 - { "20181218175730", 7 }, //7.0.0 - { "20190208150037", 7 }, //7.0.1 - { "20190314172056", 7 }, //8.0.0 - 8.0.1 - { "20190531152432", 8 }, //8.1.0 - 8.1.1 - { "20190809135709", 9 }, //9.0.0 - 9.0.1 - { "20191021113848", 10}, //9.1.0 - 9.2.0 - { "20200303104606", 10}, //10.0.0 - 10.2.0 - { "20201030110855", 10}, //11.0.0 - 11.0.1 - { "20210129111626", 10}, //12.0.0 - 12.0.1 - { "20210422145837", 10}, //12.0.2 + { "20161121", 0 }, //1.0.0 + { "20170210", 0 }, //2.0.0 - 2.3.0 + { "20170519", 1 }, //3.0.0 + { "20170710", 2 }, //3.0.1 - 3.0.2 + { "20170921", 3 }, //4.0.0 - 4.1.0 + { "20180220", 4 }, //5.0.0 - 5.1.0 + { "20180802", 5 }, //6.0.0 - 6.1.0 + { "20181107", 6 }, //6.2.0 + { "20181218", 7 }, //7.0.0 + { "20190208", 7 }, //7.0.1 + { "20190314", 7 }, //8.0.0 - 8.0.1 + { "20190531", 8 }, //8.1.0 - 8.1.1 + { "20190809", 9 }, //9.0.0 - 9.0.1 + { "20191021", 10}, //9.1.0 - 9.2.0 + { "20200303", 10}, //10.0.0 - 10.2.0 + { "20201030", 10}, //11.0.0 - 11.0.1 + { "20210129", 10}, //12.0.0 - 12.0.1 + { "20210422", 10}, //12.0.2 - 12.0.3 + { "20210607", 11}, //12.1.0 { NULL } //End. }; @@ -49,5 +52,17 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1) for (u32 i = 0; i < ARRAY_SIZE(_pkg1_ids); i++) if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 8)) return &_pkg1_ids[i]; - return NULL; + + char build_date[15]; + memcpy(build_date, (char *)(pkg1 + 0x10), 14); + build_date[14] = 0; + EPRINTFARGS("Found pkg1 ('%s').", build_date); + + if (*(pkg1 + 0xE) != KB_FIRMWARE_VERSION_MAX + 1) { + EPRINTF("Unsupported key generation!\nLockpick_RCM must be updated for support!"); + return NULL; + } + + EPRINTF("Contact if master key derivation fails."); + return &_pkg1_ids[ARRAY_SIZE(_pkg1_ids)-1]; } diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 0ba95f9..1b6e2ff 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -48,6 +48,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ + {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ }; //======================================Keys======================================// @@ -81,17 +82,19 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23}, // 8.1.0. {0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, // 9.0.0. {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. + {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. }; static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ - {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ - {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */ - {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */ - {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */ - {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ - {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ + {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */ + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */ + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */ + {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ + {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ + {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ }; // from ES @@ -107,14 +110,15 @@ static const u8 ssl_rsa_kek_source_y[0x10] __attribute__((aligned(4))) = { 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ - {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ - {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */ - {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */ - {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */ - {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ - {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ + {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */ + {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */ + {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */ + {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ + {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ + {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ }; // from SPL From 75dede5b760c04a0ce4ebb76a3087ae472d54e2e Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Jul 2021 11:17:35 -0600 Subject: [PATCH 110/166] hos: Update KB version --- source/hos/hos.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/hos/hos.h b/source/hos/hos.h index 2b89bb3..94136fa 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -38,7 +38,8 @@ #define KB_FIRMWARE_VERSION_810 8 #define KB_FIRMWARE_VERSION_900 9 #define KB_FIRMWARE_VERSION_910 10 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 +#define KB_FIRMWARE_VERSION_1210 11 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 #define HOS_PKG11_MAGIC 0x31314B50 #define HOS_EKS_MAGIC 0x30534B45 From b62b42e304f79e396350e15de560ab5102de2194 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 6 Jul 2021 11:32:01 -0600 Subject: [PATCH 111/166] Bump version to v1.9.3 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index e930c47..5175031 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,4 +1,4 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 2 +LPVERSION_BUGFX := 3 From db453b961b8a353db9eeb86250a66409a22a41af Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 11 Jul 2021 12:58:43 -0600 Subject: [PATCH 112/166] Always derive latest master key on mariko hw --- source/keys/keys.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 7b8fa8b..b52888f 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -224,12 +224,12 @@ static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx return true; } -static void _derive_master_key_mariko(u32 kb, key_derivation_ctx_t *keys) { +static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); // Relies on the Mariko KEK being properly set in slot 12 - se_aes_unwrap_key(8, 12, &mariko_master_kek_sources[kb - KB_FIRMWARE_VERSION_600]); - se_aes_crypt_block_ecb(8, 0, keys->master_key[kb], master_key_source); + se_aes_unwrap_key(8, 12, &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]); + se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); } static void _derive_master_keys_post_620(u32 pkg1_kb, key_derivation_ctx_t *keys) { @@ -301,7 +301,7 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { // verify keyblob is not corrupt se_aes_key_set(10, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i])); se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); - if (memcmp(current_keyblob, keyblob_mac, sizeof(keyblob_mac)) != 0) { + if (memcmp(current_keyblob->cmac, keyblob_mac, sizeof(keyblob_mac)) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); continue; } @@ -851,8 +851,8 @@ static void _derive_keys() { // Master key derivation if (h_cfg.t210b01) { - _derive_master_key_mariko(pkg1_id->kb, &keys); - _derive_master_keys_post_620(pkg1_id->kb, &keys); + _derive_master_key_mariko(&keys); + _derive_master_keys_post_620(KB_FIRMWARE_VERSION_MAX, &keys); } else { _derive_master_keys_post_620(pkg1_id->kb, &keys); _derive_master_keys_from_keyblobs(&keys); From d8ba2c8c94fd3a4608a97906d165e57767811d03 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 11 Jul 2021 15:00:34 -0600 Subject: [PATCH 113/166] keys: Use skb_set value --- source/keys/keys.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index b52888f..1be61d4 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -269,16 +269,16 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; - keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); - keys->sbk[1] = FUSE(FUSE_PRIVATE_KEY1); - keys->sbk[2] = FUSE(FUSE_PRIVATE_KEY2); - keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); - - if (keys->sbk[0] == 0xFFFFFFFF) { + if (h_cfg.sbk_set) { u8 *aes_keys = (u8 *)calloc(0x1000, 1); se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); free(aes_keys); + } else { + keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); + keys->sbk[1] = FUSE(FUSE_PRIVATE_KEY1); + keys->sbk[2] = FUSE(FUSE_PRIVATE_KEY2); + keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); } se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); From e9568a86251b280d48920dac614f51dd50409a02 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 11 Jul 2021 15:23:43 -0600 Subject: [PATCH 114/166] keys: Add keyslot access check --- source/keys/keys.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 1be61d4..7e16422 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -826,7 +826,21 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl free(text_buffer); } +static bool _check_keyslot_access() { + u8 test_data[AES_128_KEY_SIZE] = {0}; + const u8 test_ciphertext[AES_128_KEY_SIZE] = {0}; + se_aes_key_set(8, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); + se_aes_crypt_block_ecb(8, 0, test_data, test_ciphertext); + + return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; +} + static void _derive_keys() { + if (!_check_keyslot_access()) { + EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip!"); + return; + } + u32 start_whole_operation_time = get_tmr_us(); const pkg1_id_t *pkg1_id; @@ -948,10 +962,10 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo } u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; se_aes_key_set(ks, new_device_key, AES_128_KEY_SIZE); - se_aes_crypt_ecb(ks, 0, temp_key, AES_128_KEY_SIZE, device_master_key_source_sources[revision], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(ks, 0, temp_key, device_master_key_source_sources[revision]); se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, device_master_kek_sources[revision]); - se_aes_crypt_ecb(ks, 0, out_device_key, AES_128_KEY_SIZE, temp_key, AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(ks, 0, out_device_key, temp_key); } static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { From fe17b12ea743dffe51b01271d90d6c7015b883fa Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 12 Jul 2021 19:51:34 -0600 Subject: [PATCH 115/166] keys: Add missing master_kek_source --- source/keys/key_sources.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 1b6e2ff..d0eb78c 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -34,6 +34,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 + {0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0 }; static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { From d84ab5796a7c7839403a3135376aa9c299c74fe5 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 21 Aug 2021 16:02:19 -0600 Subject: [PATCH 116/166] Validate mariko keyslot contents; dump class keys --- README.md | 23 ++++++++++++ source/keys/key_sources.inl | 17 +++++++++ source/keys/keys.c | 74 ++++++++++++++++++++++++++++++++----- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8365383..fcdd5ef 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,29 @@ Usage * Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD * If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only) +Mariko-Specific Keys += +Mariko consoles have several unique keys and protected keyslots. To get your SBK or the Mariko specific keys, you will need to use the `/switch/partialaes.keys` file along with a brute forcing tool such as . The contents of this file are the keyslot number followed by the result of that keyslot encrypting 16 null bytes. With the tool linked above, enter them in sequence for a given keyslot you want the contents of, for example: `PartialAesKeyCrack.exe ` with the `--numthreads=N` where N is the number of threads you can dedicate to the brute force. + +The keyslots are as follows, with names recognized by `hactool`: +* 0-11 - `mariko_aes_class_key_xx` (this is not used by the Switch but is set by the bootrom; hactoolnet recognizes it but it serves no purpose) +* 12 - `mariko_kek` (not unique - this is used for master key derivation) +* 13 - `mariko_bek` (not unique - this is used for BCT and package1 decryption) +* 14 - `secure_boot_key` (console unique - this isn't needed for further key derivation than what Lockpick_RCM does but might be nice to have for your records) +* 15 - Secure storage key (console unique - this is not used on retail or dev consoles and not recognized by any tools) + +So if you want to brute force the `mariko_kek`, open your `partialaes.keys` and observe the numbers beneath keyslot 12. Here's an example with fake numbers: +``` +12 +11111111111111111111111111111111 22222222222222222222222222222222 33333333333333333333333333333333 44444444444444444444444444444444 +``` +Then take those numbers and open a command prompt window at the location of the exe linked above and type: +`PartialAesKeyCrack.exe 11111111111111111111111111111111 22222222222222222222222222222222 33333333333333333333333333333333 44444444444444444444444444444444` and if you're on a powerful enough multicore system, add ` --numthreads=[whatever number of threads]`, ideally not your system's maximum if it's, for example, an older laptop with a low-end dual core CPU. On a Ryzen 3900x with 24 threads this generates a lot of heat but finishes in about 45 seconds. + +These keys never change so a brute force need only be conducted once. + +This works due to the security engine immediately flushing writes to keyslots which can be written one 32-bit chunk at a time. See: + Building = Install [devkitARM](https://devkitpro.org/) and run `make`. diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index d0eb78c..2dd52c2 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -52,6 +52,23 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ }; +static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { + {0x20, 0x9E, 0x97, 0xAE, 0xAF, 0x7E, 0x6A, 0xF6, 0x9E, 0xF5, 0xA7, 0x17, 0x2F, 0xF4, 0x49, 0xA6}, /* Zeroes encrypted with AES Class Key 00. */ + {0x83, 0x1C, 0xC7, 0x7F, 0xB8, 0xB2, 0x66, 0x16, 0xFC, 0x6B, 0x81, 0xBB, 0xF6, 0x05, 0x07, 0x49}, /* Zeroes encrypted with AES Class Key 01. */ + {0x61, 0x19, 0xBA, 0x39, 0x6D, 0xFA, 0xF4, 0x63, 0x27, 0x8E, 0x9E, 0xB1, 0xEA, 0xD4, 0x65, 0xCC}, /* Zeroes encrypted with AES Class Key 02. */ + {0x6C, 0xDB, 0x10, 0xD4, 0x14, 0x3A, 0xBD, 0x22, 0xC9, 0xCC, 0xEF, 0xE4, 0xA0, 0x94, 0x85, 0x87}, /* Zeroes encrypted with AES Class Key 03. */ + {0xD3, 0x40, 0xC7, 0x86, 0xDC, 0x77, 0x50, 0x7C, 0x01, 0x56, 0x11, 0xDE, 0x18, 0xDF, 0x30, 0xCA}, /* Zeroes encrypted with AES Class Key 04. */ + {0xC4, 0x8B, 0xD7, 0x5A, 0x22, 0x6C, 0xF7, 0x85, 0xE4, 0xC0, 0x68, 0xFC, 0xB4, 0xD8, 0x76, 0x6C}, /* Zeroes encrypted with AES Class Key 05. */ + {0x83, 0x86, 0xEF, 0xE6, 0x6B, 0x38, 0x24, 0xD3, 0xC9, 0xB0, 0xE7, 0x03, 0x59, 0xC8, 0x54, 0xB9}, /* Zeroes encrypted with AES Class Key 06. */ + {0xDA, 0xC0, 0xD3, 0x27, 0x1D, 0x35, 0xAB, 0x4B, 0x01, 0x63, 0x90, 0xED, 0x1B, 0x5D, 0xA7, 0x6C}, /* Zeroes encrypted with AES Class Key 07. */ + {0x96, 0x75, 0x0E, 0x4F, 0xF5, 0x1A, 0xAF, 0xD4, 0x30, 0x73, 0x8C, 0x61, 0x03, 0xE5, 0xF7, 0x80}, /* Zeroes encrypted with AES Class Key 08. */ + {0x74, 0xF2, 0x1D, 0xA1, 0x4C, 0x48, 0x91, 0xE6, 0xE0, 0xD5, 0x19, 0x42, 0x2A, 0x2B, 0x5D, 0xF8}, /* Zeroes encrypted with AES Class Key 09. */ + {0x7D, 0xA6, 0xFE, 0xDA, 0xF9, 0xEF, 0x83, 0xD8, 0x29, 0x40, 0x24, 0x6D, 0x70, 0x8D, 0x99, 0x93}, /* Zeroes encrypted with AES Class Key 0A. */ + {0xF6, 0x71, 0xAD, 0xC3, 0xCD, 0xD4, 0x2F, 0x37, 0xAB, 0x50, 0x1C, 0x9B, 0xAF, 0x3B, 0xE6, 0xC3}, /* Zeroes encrypted with AES Class Key 0B. */ + {0x01, 0x96, 0x59, 0x07, 0x62, 0xF4, 0xF4, 0x2D, 0x13, 0x60, 0xD8, 0x03, 0xFB, 0xF0, 0xAE, 0xC8}, /* Zeroes encrypted with Mariko KEK. */ + {0x95, 0x48, 0xC1, 0x59, 0x0F, 0x84, 0x19, 0xC4, 0xAB, 0x69, 0x05, 0x88, 0x01, 0x31, 0x52, 0x59}, /* Zeroes encrypted with Mariko BEK. */ +}; + //======================================Keys======================================// // from Package1 -> Secure_Monitor static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { diff --git a/source/keys/keys.c b/source/keys/keys.c index 7e16422..4bc24d7 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -682,15 +682,28 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit // The security engine supports partial key override for locked keyslots // This allows for a manageable brute force on a PC -// Then we can recover the Mariko KEK, BEK, unique SBK and SSK -static void _save_mariko_partial_keys(char *text_buffer) { +// Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered +static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { + if (start + count > SE_AES_KEYSLOT_COUNT) { + return; + } + u32 pos = 0; u32 zeros[4] = {0}; u8 *data = malloc(4 * AES_128_KEY_SIZE); - for (u32 ks = 12; ks < 16; ks++) { - // First, encrypt zeros with complete key + char *text_buffer = calloc(1, 0x100 * count); + + for (u32 ks = start; ks < start + count; ks++) { + // Check if key is as expected + if (ks < ARRAY_SIZE(mariko_key_vectors)) { + se_aes_crypt_block_ecb(ks, 0, &data[0], mariko_key_vectors[ks]); + if (_key_exists(data)) { + continue; + } + } + + // Encrypt zeros with complete key se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros); - pos += s_printf(&text_buffer[pos], "%d\n", ks); // We only need to overwrite 3 of the dwords of the key for (u32 i = 0; i < 3; i++) { @@ -699,15 +712,49 @@ static void _save_mariko_partial_keys(char *text_buffer) { // Encrypt zeros with more of the key zeroed out se_aes_crypt_block_ecb(ks, 1, &data[(2 - i) * AES_128_KEY_SIZE], zeros); } + + // Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot + if (memcmp(&data[0], &data[SE_KEY_128_SIZE], AES_128_KEY_SIZE) == 0) { + continue; + } + + pos += s_printf(&text_buffer[pos], "%d\n", ks); for (u32 i = 0; i < 4; i++) { for (u32 j = 0; j < AES_128_KEY_SIZE; j++) pos += s_printf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]); - pos += s_printf(&text_buffer[pos], "\n"); + pos += s_printf(&text_buffer[pos], " "); } + pos += s_printf(&text_buffer[pos], "\n"); } free(data); - sd_save_to_file(text_buffer, strlen(text_buffer), "sd:/switch/partialaes.keys"); + + if (strlen(text_buffer) == 0) { + EPRINTF("Failed to dump partial keys."); + return; + } + + FIL fp; + u32 res = 0; + BYTE mode = FA_WRITE; + + if (append) { + mode |= FA_OPEN_APPEND; + } else { + mode |= FA_CREATE_ALWAYS; + } + + res = f_open(&fp, "sd:/switch/partialaes.keys", mode); + if (res) { + EPRINTF("Unable to write partial keys to SD."); + return; + } + + f_write(&fp, text_buffer, strlen(text_buffer), NULL); + f_close(&fp); + gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]); + + free(text_buffer); } static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { @@ -797,8 +844,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl EPRINTF("Unable to save keys to SD."); if (h_cfg.t210b01) { - memset(text_buffer, 0, text_buffer_size); - _save_mariko_partial_keys(text_buffer); + _save_mariko_partial_keys(12, 4, true); } if (_titlekey_count == 0) { @@ -836,8 +882,16 @@ static bool _check_keyslot_access() { } static void _derive_keys() { + if (!f_stat("sd:/switch/partialaes.keys", NULL)) { + f_unlink("sd:/switch/partialaes.keys"); + } + + if (h_cfg.t210b01) { + _save_mariko_partial_keys(0, 12, false); + } + if (!_check_keyslot_access()) { - EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip!"); + EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip."); return; } From 38fff7127bd3f9ccd94cf32488d736da05282b7e Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 24 Aug 2021 17:44:25 -0600 Subject: [PATCH 117/166] Use Atmosphere keygen, deprecate sept support --- .gitignore | 1 + Makefile | 10 +- README.md | 2 +- bdk/sec/tsec.c | 172 +++++------------------- bdk/sec/tsec.h | 3 +- bdk/sec/tsec_t210.h | 1 + bdk/soc/hw_init.c | 5 +- bdk/soc/t210.h | 1 - bdk/utils/types.h | 1 - keygen/tsec_keygen | Bin 0 -> 7936 bytes source/config.c | 1 - source/config.h | 1 - source/hos/fss.c | 261 ------------------------------------ source/hos/fss.h | 34 ----- source/hos/sept.c | 185 ------------------------- source/hos/sept.h | 24 ---- source/keys/key_sources.inl | 6 +- source/keys/keys.c | 253 +++++++++++----------------------- source/keys/keys.h | 10 +- source/main.c | 9 -- 20 files changed, 141 insertions(+), 839 deletions(-) create mode 100644 keygen/tsec_keygen delete mode 100644 source/hos/fss.c delete mode 100644 source/hos/fss.h delete mode 100644 source/hos/sept.c delete mode 100644 source/hos/sept.h diff --git a/.gitignore b/.gitignore index 7592fed..dfb2a80 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ research/* loader/payload_00.h loader/payload_01.h tools/bin2c/bin2c +keygen/tsec_keygen.h tools/lz/lz77 diff --git a/Makefile b/Makefile index 94d81f3..1fdc863 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,12 @@ include ./Versions.inc TARGET := Lockpick_RCM BUILDDIR := build OUTPUTDIR := output -SOURCEDIR = source +SOURCEDIR := source BDKDIR := bdk BDKINC := -I./$(BDKDIR) +KEYGENDIR := keygen +KEYGEN := tsec_keygen +KEYGENH := tsec_keygen.h VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) @@ -100,6 +103,11 @@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ @echo "Lockpick_RCM was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS) +$(OBJS): | $(KEYGENDIR) + +$(KEYGENDIR): $(TOOLS) + @cd $(KEYGENDIR) && ../$(TOOLSB2C)/bin2c $(KEYGEN) > $(KEYGENH) + $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c @mkdir -p "$(@D)" @echo Building $@ diff --git a/README.md b/README.md index fcdd5ef..8c8d4bd 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Usage * It is highly recommended, but not required, to place Minerva on SD from the latest [Hekate](https://github.com/CTCaer/hekate/releases) for best performance, especially while dumping titlekeys - the file and path is `/bootloader/sys/libsys_minerva.bso` * Launch Lockpick_RCM.bin using your favorite payload injector or chainloader * Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD -* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only) +* This release bundles the Falcon keygen from [Atmosphère-NX](https://github.com/Atmosphere-NX/Atmosphere) Mariko-Specific Keys = diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index adf5ac2..c154062 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -66,8 +66,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) { int res = 0; u8 *fwbuf = NULL; - u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; - u32 *pkg11_magic_off; bpmp_mmu_disable(); bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); @@ -125,61 +123,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } } - if (kb == KB_TSEC_FW_EMU_COMPAT) - { - // Init SMMU translation for TSEC. - pdir = smmu_init_for_tsec(); - smmu_init(0x4002B000); - // Enable SMMU - if (!smmu_is_used()) - smmu_enable(); - - // Clock reset controller. - car = page_alloc(1); - memcpy(car, (void *)CLOCK_BASE, 0x1000); - car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; - smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); - - // Fuse driver. - fuse = page_alloc(1); - memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); - fuse[0x82C / 4] = 0; - fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1; - fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1; - smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); - - // Power management controller. - pmc = page_alloc(1); - smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); - - // Flow control. - flowctrl = page_alloc(1); - smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); - - // Security engine. - se = page_alloc(1); - memcpy(se, (void *)SE_BASE, 0x1000); - smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); - - // Memory controller. - mc = page_alloc(1); - memcpy(mc, (void *)MC_BASE, 0x1000); - mc[MC_IRAM_BOM / 4] = 0; - mc[MC_IRAM_TOM / 4] = 0x80000000; - smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); - - // IRAM - iram = page_alloc(0x30); - memcpy(iram, tsec_ctxt->pkg1, 0x30000); - // PKG1.1 magic offset. - pkg11_magic_off = (u32 *)(iram + (0x7000 / 4)); - smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); - - // Exception vectors - evec = page_alloc(1); - smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); - } - //Execute firmware. HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; TSEC(TSEC_STATUS) = 0; @@ -187,91 +130,27 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - if (kb == KB_TSEC_FW_EMU_COMPAT) + if (!_tsec_dma_wait_idle()) { - u32 start = get_tmr_us(); - u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; - u32 key[16] = {0}; - u32 kidx = 0; - - while (*pkg11_magic_off != PKG11_MAGIC) + res = -3; + goto out_free; + } + u32 timeout = get_tmr_ms() + 4000; + while (!(TSEC(TSEC_CPUCTL) & TSEC_CPUCTL_KEYGEN_DONE)) + if (get_tmr_ms() > timeout) { - smmu_flush_all(); - - if (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]) - { - k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; - key[kidx++] = k; - } - - // Failsafe. - if ((u32)get_tmr_us() - start > 125000) - break; - } - - if (kidx != 8) - { - res = -6; - smmu_deinit_for_tsec(); - + res = -4; goto out_free; } - - // Give some extra time to make sure PKG1.1 is decrypted. - msleep(50); - - memcpy(tsec_keys, &key, 0x20); - memcpy(tsec_ctxt->pkg1, iram, 0x30000); - - smmu_deinit_for_tsec(); - - // for (int i = 0; i < kidx; i++) - // gfx_printf("key %08X\n", key[i]); - - // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); - - // u32 errst = MC(MC_ERR_STATUS); - // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); - // gfx_printf(" type: %02X\n", errst >> 28); - // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3); - // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); - // gfx_printf(" cid: %02x\n", errst & 0xFF); - } - else + if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) { - if (!_tsec_dma_wait_idle()) - { - res = -3; - goto out_free; - } - u32 timeout = get_tmr_ms() + 2000; - while (!TSEC(TSEC_STATUS)) - if (get_tmr_ms() > timeout) - { - res = -4; - goto out_free; - } - if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) - { - res = -5; - goto out_free; - } - - //Fetch result. - HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; - u32 buf[4]; - buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); - buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); - buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); - buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); - SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; - - memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); + res = -5; + goto out_free; } + //Fetch result. + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; + out_free:; free(fwbuf); @@ -288,3 +167,26 @@ out:; return res; } + +int tsec_run_fw(tsec_ctxt_t *tsec_ctxt) +{ + /* Ensure that the ahb redirect is enabled. */ + mc_enable_ahb_redirect(); + + /* Get bom/tom */ + u32 bom = MC(MC_IRAM_BOM); + u32 tom = MC(MC_IRAM_TOM); + + /* Override the ahb redirect extents. */ + MC(MC_IRAM_BOM) = 0x40000000; + MC(MC_IRAM_TOM) = 0x80000000; + + /* Run the fw. */ + int res = tsec_query(NULL, 0, tsec_ctxt); + + /* Reset the ahb redirect extents. */ + MC(MC_IRAM_BOM) = bom; + MC(MC_IRAM_TOM) = tom; + + return res; +} diff --git a/bdk/sec/tsec.h b/bdk/sec/tsec.h index 274b6e7..47c9f45 100644 --- a/bdk/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -24,7 +24,7 @@ typedef struct _tsec_ctxt_t { - void *fw; + const void *fw; u32 size; void *pkg1; } tsec_ctxt_t; @@ -47,5 +47,6 @@ typedef struct _tsec_key_data_t } tsec_key_data_t; int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); +int tsec_run_fw(tsec_ctxt_t *tsec_ctxt); #endif diff --git a/bdk/sec/tsec_t210.h b/bdk/sec/tsec_t210.h index 889d0d4..9d473cb 100644 --- a/bdk/sec/tsec_t210.h +++ b/bdk/sec/tsec_t210.h @@ -37,6 +37,7 @@ #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_CPUCTL 0x1100 #define TSEC_CPUCTL_STARTCPU BIT(1) +#define TSEC_CPUCTL_KEYGEN_DONE BIT(4) #define TSEC_BOOTVEC 0x1104 #define TSEC_DMACTL 0x110C #define TSEC_DMATRFBASE 0x1110 diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index 1da102f..afde017 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -253,9 +253,8 @@ static void _config_se_brom() // Enable fuse clock. clock_enable_fuse(true); - // Skip SBK/SSK if sept was run. - bool sbk_skip = b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN || FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; - if (!sbk_skip) + // Skip SBK/SSK if running on patched Erista. + if (!(FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF)) { // Bootrom part we skipped. u32 sbk[4] = { diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h index e48f53a..ac703ef 100644 --- a/bdk/soc/t210.h +++ b/bdk/soc/t210.h @@ -281,7 +281,6 @@ /*! Special registers. */ #define EMC_SCRATCH0 0x324 #define EMC_HEKA_UPD BIT(30) -#define EMC_SEPT_RUN BIT(31) /*! Flow controller registers. */ #define FLOW_CTLR_HALT_COP_EVENTS 0x4 diff --git a/bdk/utils/types.h b/bdk/utils/types.h index afa6853..57fb509 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -83,7 +83,6 @@ typedef int bool; #define BOOT_CFG_FROM_LAUNCH BIT(1) #define BOOT_CFG_FROM_ID BIT(2) #define BOOT_CFG_TO_EMUMMC BIT(3) -#define BOOT_CFG_SEPT_RUN BIT(7) #define EXTRA_CFG_DUMP_EMUMMC BIT(0) diff --git a/keygen/tsec_keygen b/keygen/tsec_keygen new file mode 100644 index 0000000000000000000000000000000000000000..b27cdaf403e05ec2bf710bbb123c50550704717a GIT binary patch literal 7936 zcmdUxWl&r}yR8Rz5AHs=y9Rd)PS7BM;O_1r!3plJgAD|Chv4q+5M0B_cMsIPm4CO+ zud{b`J-t@1x4U{*@2XY=i2YgtfM*bXPrpEbr{Vuh1ANH=fIG;y7ZD&2fK~uN_+CN+ zsX|0Or4i1QOtHN)aG|3gHWa1Rw(b6ay9|08kKrN&(k`=H=Id zp&(yUsQ>g|$^FX0SH6w+z3QY_YW|a(ebrL0eA73t+Vz!h8s}BN@ogR0S0DUJ&3|%l z{>?xBTiqMEU&m)(`BsPXs--~Jf^L8JPw}@of_&Nj^9=%DsrJf?SF*qIE%&B3|M4eZ zHRdbd<}>*x_cqU4{%xMOx;IVnTK87Z{?Gh1uUhOM|1ID3>Ic5^;vceugaHzOdv-;D zu@b;UI2#hs)A4eJM4y}uNX~&s&V@|QgSr_9+)My&CIL570B|-sxCR~EfnHk&Sa@Vh z?0~;n2MGH?0`4JeKsCcP%eCtOlm!3)fFV2t3HVP3;-w@}8DMmC52!)(wSfdYLI|Hg z0+QPSU=TF83p%?BoDE&u1Gu>RKWWJ4pD?n2(`kU#ZFzuk>$ET)6yT-xCGh|<<`lZ6 zDy8uF3jS~Q?`duMf7^c?ioeePZFhgy{$KpO{pSB6!ry(QQKLF`#GjOZP>EUP!%Caf zd+}zKt*dfrMH4~Wn~KQ^_2C&Hf6BVIThWW@cHd;LN6&5qw`)23nV$5l;Hioww}^(K z-^Y|qtx=kI;qPV@2&a`VIWy5t+8-RZoX|d6hZ3H2B^b|f=*~|qSivDG!vktqIBgq@ zn8fqA$k@vfInVlnuFD&bGbAQ!uk^9tN_f@Y`E@Xpj5fssh$R4V;*caTtXkqE-QVE2 zetccnoQF!tPZas_?L+VYQ3~~TQKQ7ESu)~oWVWUPzC+frCRg2J#5pt3|L^{h2_u}=9WFw|s(sj=YvAgN+i;4jMhwc@g&2)7TD&b_ ziBQge-pwstYvYJ5<8nBk;-N zuUOx+Hieu1bVtZXY{$i?ySBBGWr(`}*Z#UJK<=K`sa#7P`JBOU`SZc`4O6q$_EOl=~%%V)9Wdr*O|r_q#cv z8T5R{u3b=23lZu~G$XJkbRrH(L-}Xb`pX7@C9dry_NPUFUY29PVkj zCNMDMglF$%yR$!*1lU2RoGJABbwZI7IF z6tSc12`K0Aq4#>9183Za^YJq1UwtG#?AtQGdrDgQH5U%oaA6z+4^AeZoQA1wexy~z z zBcEhhSZc9pq!C3vr$nD6ZnZep5S=u^o%l~WJt?;nKE&*ybvIJyvC($a>+l;IugFeO z*k0)zqiT8@dq{o0&q)>UhIq(7aQr?$LL$MXDDb?Z1aMeSE-7WMKCR{WTvmIWmm>K z`e-jJqJ+5{EIB>O?s^PHhUs#D?zPkv7tM(auUaZrhgaRXg>y|+k5@ln`^>bPk!I_$ z_>%ubBh^sIrS45l2Rl{P`eVS~095S4%uk2ZAPS!!lhU{o3z7GGM28I7Qf1(;qFaC=T(s zHu(`b=%oxSaU*$#ye` zk;k!>gaoyq#6&AJf(}T^Kgi^wxVl*KBq!Ts#?eA92*;P@IDInzjyLt6^|%;_ASG># zZcdhWSQ7xpS7i?8Po*2%!2M*-!?QdWaMOdhBicPr?o$uGHP8MPNqCoeNUP@FF8Zka z>hv{ACtaG=)>{_uhZuX=qEJp;VX|_#pQ654%k}k|{sFKnrH+RUq^_NuOKQY7ODK;` zj^nIAMLzP%q4&+|g};2isQgCgj!%5)EUZiA%dExr-EL@wb}K-s628z>2l)V@@p-2W zKh$0W%O+v;x@E$#D8nIkl&CX^8=yIy8sABrw zK1+Wg7nMOe4Y|v4+3k{zLw>JCVy^UX zj=xN`iD|fw3=KGCA@^-1f8YIL9z|ogX`vO-k2W!Fc|gG=iwDQxb@H-JypMe}{A5+d z}XiB<*mYHhikgMdqzLeB0~hqY|vf2n7cb~qaL zNm5D5j|_$N(WT~VbYpIpmH?;#q93pXB)sRE2Yz5gcXBg``AF@$<2gk4J6HO;Ts4;j zJ;a;P`rZoCa%-!bido}8%(EDmG#8&)HOh`o>nGgoulD%BLY;u-JC2>fe=qn#?;1bd z;q!T!IYf|Hnh#b)?bYD5M=cD>L}SRteem$zs-QY&Co^O7cE5-u=(kpC#dZaaAbXMB z&#MP8U4zl3cEmSUJduL2Qx6k3^^ODfd~3BzxXo;ILy~|hiODhjC|@Uk+2*Vb^2L_b zQ>AWxHe%61pt`4O5C-}`e2r6X`y8LHg+FoE7H;7l_=32#U1%7bkU15A(3R#gzdc5d z^RfhtH^L`_Ui}=u0%BhyH6m$7Q<_VZ$7q0#pxJugM7H_^2&Dj>6yke1Sb z8E~yMaQGlvu5U*KISd+FCLZur4N`@e=^mf%gHd{nN+)AVr(=_q#8d(+_EYX0dN-f!)4;pk$)rCGOpKwp6R3%o2t(IgN zUBm@|aU#0UtJh7Man7m@m)tXN=Z>NJs5Er8LO=A7NSc9G@e#wV`$mPky+7CT~v&DKGj2_MS-)_*SDWfu*2qJ!>eD9702OBqhe zZ}aW>a%fs;ar`&?vZd6L;!(U7&WTJ9_y8~p#>b41Y;EZ-XlX~@W>~Gnj!x#%Na=E%$kA&Ti4Yd*!Ovh>)_=2J zV<}}0DTW)$Jk|yrnh-h(qD&X5G*v>44oe1d@&O&Re#MJzn$HOoD2ZqhrHTfAxA=WV zv_EIuj$kjj;`Muguo?wd(7|mPZI2) z>m7$@9&Uweo(8(hI2W|;&htel=;5Oa|4DO(e30vp2$vbYEx8Q@Qc+?52LvOj+-kq3 zH5@LoStGI=?3isOY-Me!}n<;yP*QA z)x?jJm6&5XdP39`zam4)lGIjx=p5RaYop6Gla3HLdv_T&Gx$TA0bX%0^u(+c2)aFk zIbr#Jg#)Wc{($YRARO#tNabd0R=tB%pxYf8zXw9_6em`G4CG13rH)#opltKr_5QwT zNl&PQdU)H7?UWszz^0%~XNGU`_mJ#BJOr3~Y_vF2b6(x)dUzMo;1e~tlSZ9ujVYW_ z!LcJlrwkO!2cVG^Ia!MK!6;PZpgAXTjA}XAUcMvV4PH$wU;O2lTC(jGQi!n`gr1SP z{`05cW2uTC?}kf_XK3$4>O?b#j+APzhS2E|5Ca1Zn&@iWfJyC-LX??fq`C?K=9D*7MI=x)!zvb%NHicrQCphqu=yNS;C0`QJ|vg}9i zjRt921|2Y*i6-k;9ujcHb8SS!OX|HFu-v|ENb%F4fNS84r_17_p1NzZu@W~(!12_z z8aKdJBCSlR3!Y`X!b2T?#}w!_`p2~0s^;>fO!aERVXoK#hv24O0oKXM4$C0&YGTZS zT&7V1|C5#G6Nh^so?!tj*lTEC*Qno#z}hBHi1kzX)O5HhMY^(3m3ZKa`2|`r2gQo+ zdZ&4O?VeBl26G4K$wsp=BgS{mkmrZr@<)5@kveM8V5PdY6@Of+piUvIJx;^P{)e&O zMS5w0eO-Z7_;u8yyS(`$u#fA^n*cS%c^r4v6m*1Idvi%`wcR6;z~cY~wg6(BzA8whFz;)trA3 zv|`hdj@MyXwfgCd=!&qBz<2J?>l@KOTC%~*?pRRUqD*}--I6gBYQoab!NcygM?Q&! z?3(=O&9yi|D^k`?!8t$jEw2|FL%4H zstHyQxk(f!)~XJ@tr`?hA#eSP8o5 z;Fm0W{;&%O*A-@4=WHX`ggY2SAT|3bd6zc!qXltBJviad5|;>t_QI&x#u43a;17BT5Ts&w(oZUt84nZ`L9!np?{RFe_) z65{AZ%ACNE9cwiv^D`lG!=Yv`S2sr^gfy~MW!m9Yg9Rkqo|Jl0mF$qz_4y&0H<*3*CK_Cvwoq*oQ{>>mmv00S zNS%dOO9X$aPD_dTo~^^VL+*w*lUDoRRakSPGjEp3-04H-2xgXT%fWPrMBXH4YKAf_08u zLaMRr3lT(x(Q_oI0OF+V2cw6h7_<xFZ5} z{fv{AO&yj%ovJRh>WB831MSFs_gjhx%dZ#$#$LvMniDu8J9Rf%%MC>pr>zN~i&zW) zT6oDdJNXfEQ{viYg#BZTB>;m;IR$}tlq*omn{t3S(ATqJ20ZGF(@8Obq7d~HFqFuu zREn}jf3&5v?gWqd&9lVdyPKT>)6 zaBL8{GD4^57I^X%M?Tvgc3Q_18-;qf2MS@w4F*TC7*g~?xJ&=8Xl^%$zei%*MGJ7*i1 z(BOLiy$}24ez(%A>BUdrE{&8Z4O8!FkYlVH5YoPpc zS&<{_%kdM}5!+_)4^&vD68&_nhgY7VtP^-5jl$ZT!xBt9y<|zo$Q@|o=w*qy4fMn> zC~GXqDT6vK`lV|(`gP12nAsAk0T-3}If+mn4r+ms-E>fE44WD+odi?|l{-@In?7N1 z;%6vcl5Zkwe2YJ1oD7TCX?n+B0%fAWLzSPv9=QS6gCK^V5h9T?omfCnH789pE4nPu z`T{#E5~5Y$E*Q7ClyK*0?U?ihrrA!B`F?O2`lZ-acHImU8aWsZ1`_323YBVINBWC3 z*QOKW?qT5;RibXzArpSGZ%n=Ca=;WBcY`e$?5yW(3?_KKAV0iyPIPGxL{g&jDawsr zYdD7)O40kcv5V^})bd-q)UZoOVyTSuo58N_=3%w2Bu_$AL|X^#jB2=I?nX%5dt%Gd z#9iEP_JszhYXXCIu6iw$TGppe;BrPsF-Z^1W-T}?xAd+09r^E(zi?MF*$<<*(O5bK zW~RBxk@d1sT`-~)NcLnA4;p3ExP>D2AP#t3dQ=_`={jj&jOdLjZ2T}vQd)I6lw)9E zv%|>w3;d?es_(-Y`-xzAEBqmt@Xv21TBejYp-Plb4}AxQZ^BFvvQ5uD2!2WAO#*Tuk6>{yEEZ9x+s-KKA}zPII^${`WQzZt$)5Ei#dK1H z_W?vf%(7C3(Z`+**#N#DiMs4n@0nR3R6a_hhcx-J^qgJ=;SgIsl?vB%Q_5vE9%)sI z9hnUfI1VaEU)AP$2kJ^&IU3G64)P-fEWNujBR)4TLpMj1pv)Hs z1?nf{(T4Ucu(ltpf$PU*{1HT$B^EBIiEZ8RigKPmHbaV34N+?f3la!T;<9t@S-%g2 z;leOYZn>gK#33sUeW1p0piab4HhbbnjCSgX`-I)BQGC(h$7sXEEP zds)jzbO0vWPgf~`DG0H*V_+L)mH-TQ@)8>8l^w%pnmSt$R?2lBcf}<#^xXP!iU7?q zd`zm9FUNvwHHwC6Nq26tN1I;@dIPagyLBigJ`r<}Bs`7ao{BWXG2``Z+e~q(d;z~u z)&Y%-d(@`!x0IXPHS=`!m^>BSp<~}^pj(#}9sGjf&{t=fzip%3sn9Jm3qL(@*pM8- zX_I>wLIMg6nopMm)u%I<6Uj{cJYDg-4UZko4Gfxtv3}2mvvz?fy&Jg_>d|g zBc%<2ZgTQYT|lETzpS`-1Xs2IUdKJ_sTsi`03JTrr}i1Miqmfi!~H3>x@+ok{ZwLr z`hj~t?>Q; zZ7x!laJ@}kA+DZno7hNFL%%`Ww&+<4rrt8!R4F$jmix0^3UmpgDoE*f{+13z0 z^X)J1ct}AgU}alp$*1@aF4Gi;)$KO1bqzW$q#NDuUnWnIs;L7$)VKY@Kzw&P1jgYb7Q@+QPQg6=ibXD&xD)hngE zU5vz!giAsuR+n2YA-eKE#^C27tD>lcYt$#z@Nnrf5#pl@8hF`sbM$a31mh~DNquA+ z@3Y!fNZ88vuEa&D8ED}=j7kx3YsQet_TjXQaqk%cPF4roTxT^j-SH6zn^V~;U~6>t z2iZ$%&o#PKxP_c;ntBjc2##fF$}rFEPwN-Z3S1eq&0*Q@@vqgaAVOxhx^}BzWsZGi z7K#?u_SOZ@$|~e8hTg#AFvv_AG=@jU`CoA^t`L8*Hj#@r@F_0AqW|UF14Ju2Ryc-I ez*. - */ - -#include - -#include "fss.h" -#include "hos.h" -#include "../config.h" -#include -#include -#include "../storage/emummc.h" -#include - -#include -#define DPRINTF(...) - -extern hekate_config h_cfg; - -extern bool is_ipl_updated(void *buf, char *path, bool force); - -// FSS0 Magic and Meta header offset. -#define FSS0_MAGIC 0x30535346 -#define FSS0_META_OFFSET 0x4 -#define FSS0_VERSION_0_17_0 0x110000 - -// FSS0 Content Types. -#define CNT_TYPE_FSP 0 -#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor). -#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw). -#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw). -#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader). -#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys). -#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition). -#define CNT_TYPE_BMP 7 -#define CNT_TYPE_EMC 8 -#define CNT_TYPE_KLD 9 // Kernel Loader. -#define CNT_TYPE_KRN 10 // Kernel. -#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload. - -// FSS0 Content Flags. -#define CNT_FLAG0_EXPERIMENTAL BIT(0) - -// FSS0 Meta Header. -typedef struct _fss_meta_t -{ - u32 magic; - u32 size; - u32 crt0_off; - u32 cnt_off; - u32 cnt_count; - u32 hos_ver; - u32 version; - u32 git_rev; -} fss_meta_t; - -// FSS0 Content Header. -typedef struct _fss_content_t -{ - u32 offset; - u32 size; - u8 type; - u8 flags0; - u8 flags1; - u8 flags2; - u32 rsvd1; - char name[0x10]; -} fss_content_t; - -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) -{ - FIL fp; - - bool stock = false; - int sept_used = 0; - - // Skip if stock and Exosphere and warmboot are not needed. - if (!sept_ctxt) - { - bool pkg1_old = ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620; - bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable; - - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) - { - if (!strcmp("stock", kv->key)) - if (kv->val[0] == '1') - stock = true; - } - -#ifdef HOS_MARIKO_STOCK_SECMON - if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) -#else - if (stock && emummc_disabled && pkg1_old) -#endif - return 1; - } - - if (f_open(&fp, path, FA_READ) != FR_OK) - return 0; - - void *fss = malloc(f_size(&fp)); - - // Read first 1024 bytes of the fss file. - f_read(&fp, fss, 1024, NULL); - - // Get FSS0 Meta header offset. - u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET); - fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr); - - // Check if valid FSS0 and parse it. - if (fss_meta->magic == FSS0_MAGIC) - { - bool mariko_not_supported = false; - if (h_cfg.t210b01 && (fss_meta->version < FSS0_VERSION_0_17_0)) - { - gfx_con.mute = false; - mariko_not_supported = true; - } - - gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" - "Max HOS supported: %d.%d.%d\n" - "Unpacking and loading components.. ", - fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, - fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); - - if (mariko_not_supported) - { - EPRINTF("\nMariko not supported on < 0.17.0!"); - goto fail; - } - - if (!sept_ctxt) - { - ctxt->atmosphere = true; - ctxt->fss0_hosver = fss_meta->hos_ver; - } - - // Parse FSS0 contents. - fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off); - void *content; - for (u32 i = 0; i < fss_meta->cnt_count; i++) - { - content = (void *)(fss + curr_fss_cnt[i].offset); - - // Check if offset is inside limits. - if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size) - continue; - - // If content is experimental and experimental flag is not enabled, skip it. - if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_experimental) - continue; - - // Parse content. - if (!sept_ctxt) - { - // Prepare content context. - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_KIP: - if (stock) - continue; - merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); - mkip1->kip1 = content; - list_append(&ctxt->kip1_list, &mkip1->link); - DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); - break; - - case CNT_TYPE_KRN: - if (stock) - continue; - ctxt->kernel_size = curr_fss_cnt[i].size; - ctxt->kernel = content; - break; - - case CNT_TYPE_EXO: - ctxt->secmon_size = curr_fss_cnt[i].size; - ctxt->secmon = content; - break; - - case CNT_TYPE_EXF: - ctxt->exofatal_size = curr_fss_cnt[i].size; - ctxt->exofatal = content; - break; - - case CNT_TYPE_WBT: - if (h_cfg.t210b01) - continue; - ctxt->warmboot_size = curr_fss_cnt[i].size; - ctxt->warmboot = content; - break; - - default: - continue; - } - - // Load content to launch context. - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, content, curr_fss_cnt[i].size, NULL); - } - else - { - // Load sept content directly to launch context. - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_SP1: - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL); - break; - case CNT_TYPE_SP2: - if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15)) - { - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL); - sept_used = 1; - goto out; - } - break; - default: - break; - } - } - } - -out: - gfx_printf("Done!\n"); - f_close(&fp); - - return (!sept_ctxt ? 1 : sept_used); - } - -fail: - f_close(&fp); - free(fss); - - return 0; -} - -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt) -{ - LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link) - { - if (!strcmp("fss0", kv->key)) - return parse_fss(NULL, kv->val, sept_ctxt); - } - - return 0; -} diff --git a/source/hos/fss.h b/source/hos/fss.h deleted file mode 100644 index 3f56d7c..0000000 --- a/source/hos/fss.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 . - */ - -#ifndef _FSS_H_ -#define _FSS_H_ - -#include "hos.h" - -typedef struct _fss0_sept_t -{ - u32 kb; - ini_sec_t *cfg_sec; - void *sept_primary; - void *sept_secondary; - -} fss0_sept_t; - -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt); -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt); - -#endif diff --git a/source/hos/sept.c b/source/hos/sept.c deleted file mode 100644 index 873b7ab..0000000 --- a/source/hos/sept.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 . - */ - -#include - -#include "hos.h" -#include "fss.h" -#include "sept.h" -#include "../config.h" -#include -#include -#include -#include -#include -#include -#include -#include "../storage/nx_emmc.h" -#include -#include -#include -#include -#include - -#include - -#define PATCHED_RELOC_SZ 0x94 - -#define WB_RST_ADDR 0x40010ED0 -#define WB_RST_SIZE 0x30 - -u8 warmboot_reboot[] = { - 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 - 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 - 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0xFE, 0xFF, 0xFF, 0xEA, // LOOP - 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 - 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 -}; - -#define SEPT_PRI_ADDR 0x4003F000 - -#define SEPT_PK1T_ADDR 0xC0400000 -#define SEPT_PK1T_STACK 0x40008000 -#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) -#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) -#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) -#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) - -extern u32 color_idx; -extern boot_cfg_t b_cfg; -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); - -int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) -{ - FIL fp; - bool fss0_sept_used = false; - - // Copy warmboot reboot code and TSEC fw. - memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); - memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); - *(vu32 *)SEPT_TCSZ_ADDR = tsec_size; - - LIST_INIT(ini_sections); - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - { - bool found = false; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Only parse non config sections. - if (ini_sec->type == INI_CHOICE && strcmp(ini_sec->name, "config")) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("fss0", kv->key)) - { - fss0_sept_t sept_ctxt; - sept_ctxt.kb = kb; - sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR; - sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR; - fss0_sept_used = parse_fss(NULL, kv->val, &sept_ctxt); - - found = true; - break; - } - } - } - if (found) - break; - } - } - - if (!fss0_sept_used) - { - // Copy sept-primary. - if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) - goto error; - - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) - { - if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) - goto error; - } - - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - } - - // Save auto boot config to sept payload, if any. - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t)); - - tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) - { - free(tmp_cfg); - goto error; - } - - f_lseek(&fp, PATCHED_RELOC_SZ); - f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); - - f_close(&fp); - - sd_unmount(); - - u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); - - void (*sept)() = (void *)pk1t_sept; - - reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); - - // Patch SDRAM init to perform an SVC immediately after second write. - PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; - PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; - // Set SVC handler to jump to sept-primary in IRAM. - PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; - PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - - hw_reinit_workaround(false, 0); - - (*sept)(); - -error: - EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again."); - display_backlight_brightness(100, 1000); - - btn_wait(); - - return 0; -} \ No newline at end of file diff --git a/source/hos/sept.h b/source/hos/sept.h deleted file mode 100644 index 086d50d..0000000 --- a/source/hos/sept.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 . - */ - -#ifndef _SEPT_H_ -#define _SEPT_H_ - -#include - -int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb); - -#endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 2dd52c2..dab8a4b 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,7 +19,7 @@ static const u8 null_hash[0x20] __attribute__((aligned(4))) = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; -static const u8 keyblob_key_source[][0x10] __attribute__((aligned(4))) = { +static const u8 keyblob_key_sources[][0x10] __attribute__((aligned(4))) = { {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 @@ -146,7 +146,7 @@ static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { // from FS static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] __attribute__((aligned(4))) = { +static const u8 bis_key_sources[3][0x20] __attribute__((aligned(4))) = { {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, diff --git a/source/keys/keys.c b/source/keys/keys.c index 4bc24d7..765ac5a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,17 +16,17 @@ #include "keys.h" +#include "../../keygen/tsec_keygen.h" + #include "../config.h" #include #include #include "../gfx/tui.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" -#include "../hos/sept.h" #include #include #include -#include #include #include #include @@ -122,108 +122,6 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { return pkg1; } -#define RELOC_META_OFF 0x7C - -static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { - sd_mount(); - if (!f_stat("sd:/sept/payload.bak", NULL)) { - f_unlink("sd:/sept/payload.bin"); - f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); - } - - if (!h_cfg.sept_run) { - // bundle lp0 fw for sept instead of loading it from SD as hekate does - sdram_lp0_save_params(sdram_get_params_patched()); - - FIL fp; - if (f_stat("sd:/sept", NULL)) { - EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); - return true; - } - // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) { - if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { - EPRINTF("Unable to backup payload.bin."); - return false; - } - } - // write self to payload.bin to run again when sept finishes - volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); - u32 payload_size = relocator->end - IPL_LOAD_ADDR; - if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - return false; - } - gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); - if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - f_close(&fp); - return false; - } - gfx_printf(" done"); - f_close(&fp); - gfx_printf("%k\nRebooting to sept...\n\n", colors[(color_idx++) % 6]); - sdmmc_storage_end(&emmc_storage); - if (!reboot_to_sept((u8 *)tsec_fw, tsec_size, kb)) { - return false; - } - } else { - se_aes_key_get(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, out_key, AES_128_KEY_SIZE); - } - - return true; -} - -static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx_t *keys) { - tsec_ctxt->fw = _find_tsec_fw(tsec_ctxt->pkg1); - if (!tsec_ctxt->fw) { - EPRINTF("Unable to locate TSEC firmware."); - return false; - } - - minerva_periodic_training(); - - tsec_ctxt->size = _get_tsec_fw_size((tsec_key_data_t *)(tsec_ctxt->fw + TSEC_KEY_DATA_OFFSET)); - if (tsec_ctxt->size > PKG1_MAX_SIZE) { - EPRINTF("Unexpected TSEC firmware size."); - return false; - } - - if (kb >= KB_FIRMWARE_VERSION_700) { - if (!_handle_sept(tsec_ctxt->fw, tsec_ctxt->size, kb, keys->master_key[KB_FIRMWARE_VERSION_MAX])) { - return false; - } - } else if (kb == KB_FIRMWARE_VERSION_620) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, tsec_ctxt->fw, tsec_ctxt->size); - tsec_ctxt->fw = tsec_paged; - } - - int res = 0; - u32 retries = 0; - - // mc_disable_ahb_redirect(); - - while (tsec_query(keys->tsec_keys, kb, tsec_ctxt) < 0) { - memset(keys->tsec_keys, 0, sizeof(keys->tsec_keys)); - retries++; - if (retries > 15) { - res = -1; - break; - } - } - - // mc_enable_ahb_redirect(); - - if (res < 0) { - EPRINTFARGS("ERROR %x dumping TSEC.\n", res); - return false; - } - - TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); - return true; -} - static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); @@ -232,39 +130,41 @@ static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); } -static void _derive_master_keys_post_620(u32 pkg1_kb, key_derivation_ctx_t *keys) { - // on firmware 6.2.0 only, the tsec_root_key is available - if (pkg1_kb == KB_FIRMWARE_VERSION_620 && _key_exists(keys->tsec_keys + AES_128_KEY_SIZE)) { - se_aes_key_set(8, keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) - se_aes_crypt_block_ecb(8, 0, keys->master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, keys->master_kek[6], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mks) - se_aes_crypt_block_ecb(8, 0, keys->master_key[6], master_key_source); +static int _run_ams_keygen(key_derivation_ctx_t *keys) { + tsec_ctxt_t tsec_ctxt; + tsec_ctxt.fw = tsec_keygen; + tsec_ctxt.size = sizeof(tsec_keygen); + int res = tsec_run_fw(&tsec_ctxt); + + if (res) { + EPRINTFARGS("ERROR %d running keygen.\n", res); } - if (pkg1_kb >= KB_FIRMWARE_VERSION_620) { - // derive all lower master keys in case keyblobs are bad - // handle sept version differences - for (u32 kb = pkg1_kb == KB_FIRMWARE_VERSION_620 ? KB_FIRMWARE_VERSION_620 : KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { - for (u32 i = kb; i > 0; i--) { - se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); - } - se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); - if (!_key_exists(keys->temp_key)) { - break; - } - memcpy(keys->master_key[kb - 1], keys->master_key[kb], AES_128_KEY_SIZE); - memset(keys->master_key[kb], 0, AES_128_KEY_SIZE); - } - if (_key_exists(keys->temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.", pkg1_kb); - memset(keys->master_key, 0, sizeof(keys->master_key)); - } + return res; +} + +static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys) { + if (!h_cfg.t210b01) { + se_aes_crypt_block_ecb(13, 0, keys->master_kek[KB_FIRMWARE_VERSION_MAX], master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620]); // mkek = unwrap(tsec_root, mkeks) + se_aes_key_set(8, keys->master_kek[KB_FIRMWARE_VERSION_MAX], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) + se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); + } + + // Derive all lower master keys + for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { + se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); + } + se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); + + if (_key_exists(keys->temp_key)) { + EPRINTF("Unable to derive master key."); + memset(keys->master_key, 0, sizeof(keys->master_key)); } } -static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { +static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; @@ -281,15 +181,13 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); } - se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); - if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblobs."); } for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); - se_aes_crypt_block_ecb(8, 0, keys->keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) + se_aes_crypt_block_ecb(12, 0, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(14, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) @@ -335,18 +233,18 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { _get_device_key(8, keys->temp_key, key_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_source[0] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_sources[0] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_sources[0] + 0x10); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_source[2] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_sources[1] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_sources[1] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_sources[2] + 0x00); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_sources[2] + 0x10); memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); } -static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_count) { +static void _derive_misc_keys(key_derivation_ctx_t *keys) { if (_key_exists(keys->master_key[0])) { _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x00, header_key_source + 0x00); @@ -359,10 +257,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_cou se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); } - if (_key_exists(keys->master_key[*derivable_key_count])) { - *derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1; - } - for (u32 i = 0; i < *derivable_key_count; i++) { + for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) { if (!_key_exists(keys->master_key[i])) continue; for (u32 j = 0; j < 3; j++) { @@ -666,7 +561,9 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return false; } - if (!_derive_sd_seed(keys)) { + if (!sd_mount()) { + EPRINTF("Unable to mount SD."); + } else if (!_derive_sd_seed(keys)) { EPRINTF("Unable to get SD seed."); } @@ -757,7 +654,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { free(text_buffer); } -static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { +static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time) { char *text_buffer = NULL; if (!sd_mount()) { EPRINTF("Unable to mount SD."); @@ -771,7 +668,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(aes_key_generation_source); SAVE_KEY(bis_kek_source); SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0); - SAVE_KEY_FAMILY(bis_key_source, 0); + SAVE_KEY_FAMILY(bis_key_sources, 0); SAVE_KEY_VAR(device_key, keys->device_key); SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); @@ -789,7 +686,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0); SAVE_KEY_FAMILY_VAR(keyblob_key, keys->keyblob_key, 0); - SAVE_KEY_FAMILY(keyblob_key_source, 0); + SAVE_KEY_FAMILY(keyblob_key_sources, 0); SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); @@ -823,18 +720,24 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(ssl_rsa_kek_source_y); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); - _save_key("tsec_key", keys->tsec_keys, AES_128_KEY_SIZE, text_buffer); - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - _save_key("tsec_root_key", keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); + SAVE_KEY_VAR(tsec_key, keys->tsec_key); + + const u32 root_key_ver = 2; + char root_key_name[21] = "tsec_root_key_00"; + s_printf(root_key_name + 14, "%02x", root_key_ver); + _save_key(root_key_name, keys->tsec_root_key, AES_128_KEY_SIZE, text_buffer); + + s_printf(root_key_name + 14, "dev_%02x", root_key_ver); + _save_key(root_key_name, keys->tsec_root_key_dev, AES_128_KEY_SIZE, text_buffer); end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/prod.keys"; - if (fuse_read_odm(4) & 3) + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) s_printf(&keyfile_path[11], "dev.keys"); FILINFO fno; @@ -902,28 +805,30 @@ static void _derive_keys() { if (!pkg1) { return; } - - u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; - bool res = true; - key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; - - if (!h_cfg.t210b01) { - tsec_ctxt_t tsec_ctxt; - tsec_ctxt.pkg1 = pkg1; - res =_derive_tsec_keys(&tsec_ctxt, pkg1_id->kb, &keys); - } free(pkg1); - if (res == false) { - return; - } + + key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; // Master key derivation if (h_cfg.t210b01) { _derive_master_key_mariko(&keys); - _derive_master_keys_post_620(KB_FIRMWARE_VERSION_MAX, &keys); + _derive_master_keys_from_latest_key(&keys); } else { - _derive_master_keys_post_620(pkg1_id->kb, &keys); - _derive_master_keys_from_keyblobs(&keys); + int res = _run_ams_keygen(&keys); + if (res) { + EPRINTF("Unable to run keygen."); + return; + } + + u8 *aes_keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); + memcpy(&keys.tsec_root_key_dev, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&keys.tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + free(aes_keys); + + _derive_master_keys_from_latest_key(&keys); + _derive_keyblob_keys(&keys); } TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); @@ -932,7 +837,7 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - _derive_misc_keys(&keys, &derivable_key_count); + _derive_misc_keys(&keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; @@ -943,7 +848,7 @@ static void _derive_keys() { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); } - _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time, derivable_key_count); + _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time); } void dump_keys() { diff --git a/source/keys/keys.h b/source/keys/keys.h index b3018a5..32d7fb6 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -108,7 +108,9 @@ typedef struct { master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - tsec_keys[AES_128_KEY_SIZE * 2]; + tsec_key[AES_128_KEY_SIZE], + tsec_root_key[AES_128_KEY_SIZE], + tsec_root_key_dev[AES_128_KEY_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; } key_derivation_ctx_t; @@ -137,9 +139,9 @@ typedef struct { // save key with different name than variable #define SAVE_KEY_VAR(name, varname) _save_key(#name, varname, sizeof(varname), text_buffer) // save key family wrapper -#define SAVE_KEY_FAMILY(name, start) _save_key_family(#name, name, start, sizeof(name) / sizeof(name[0]), sizeof(name[0]), text_buffer) +#define SAVE_KEY_FAMILY(name, start) _save_key_family(#name, name, start, ARRAY_SIZE(name), sizeof(*(name)), text_buffer) // save key family with different name than variable -#define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, sizeof(varname) / sizeof(varname[0]), sizeof(varname[0]), text_buffer) +#define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, ARRAY_SIZE(varname), sizeof(*(varname)), text_buffer) void dump_keys(); diff --git a/source/main.c b/source/main.c index deee446..1eea1fb 100644 --- a/source/main.c +++ b/source/main.c @@ -395,15 +395,6 @@ void ipl_main() h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; emu_cfg.enabled = !h_cfg.emummc_force_disable; - if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) - { - if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) { - h_cfg.emummc_force_disable = true; - emu_cfg.enabled = false; - } - dump_keys(); - } - // Grey out emummc option if not present. if (h_cfg.emummc_force_disable) { From a89e9b4d7f16449f3ab5338760890fb4866985c8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 28 Aug 2021 12:35:26 -0600 Subject: [PATCH 118/166] Support dev key dumping on all consoles --- bdk/sec/se.c | 4 +- bdk/sec/se.h | 2 +- bdk/soc/fuse.c | 9 ++ bdk/soc/fuse.h | 1 + source/keys/key_sources.inl | 46 +++++++++ source/keys/keys.c | 189 ++++++++++++++++++++++-------------- source/keys/keys.h | 3 +- 7 files changed, 176 insertions(+), 78 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 706e83d..a879cb0 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -181,7 +181,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr return res; } -static void _se_aes_ctr_set(void *ctr) +static void _se_aes_ctr_set(const void *ctr) { u32 data[SE_AES_IV_SIZE / 4]; memcpy(data, ctr, SE_AES_IV_SIZE); @@ -383,7 +383,7 @@ int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) return se_aes_crypt_ecb(ks, enc, dst, SE_AES_BLOCK_SIZE, src, SE_AES_BLOCK_SIZE); } -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, const void *ctr) { SE(SE_SPARE_REG) = SE_ECO(SE_ERRATA_FIX_ENABLE); SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); diff --git a/bdk/sec/se.h b/bdk/sec/se.h index a52fd53..2a2f8cd 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -41,7 +41,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, const void *ctr); int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size); int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index 0a37a4b..e350b64 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -76,6 +76,15 @@ u32 fuse_read_odm_keygen_rev() return 0; } +u32 fuse_read_bootrom_rev() +{ + u32 rev = FUSE(FUSE_SOC_SPEEDO_1_CALIB); + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + return rev; + else + return rev | (1 << 12); +} + u32 fuse_read_dramid(bool raw_id) { u32 dramid = (fuse_read_odm(4) & 0xF8) >> 3; diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h index 810efd6..481923c 100644 --- a/bdk/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -94,6 +94,7 @@ enum void fuse_disable_program(); u32 fuse_read_odm(u32 idx); u32 fuse_read_odm_keygen_rev(); +u32 fuse_read_bootrom_rev(); u32 fuse_read_dramid(bool raw_id); u32 fuse_read_hw_state(); u32 fuse_read_hw_type(); diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index dab8a4b..560efac 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -52,6 +52,21 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ }; +static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { + {0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */ + {0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */ + {0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */ + {0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */ + {0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */ + {0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */ + {0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */ + {0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */ + {0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04}, /* Master key 07 encrypted with Master key 08. */ + {0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */ + {0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */ + {0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C}, /* Master key 0A encrypted with Master key 0B. */ +}; + static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { {0x20, 0x9E, 0x97, 0xAE, 0xAF, 0x7E, 0x6A, 0xF6, 0x9E, 0xF5, 0xA7, 0x17, 0x2F, 0xF4, 0x49, 0xA6}, /* Zeroes encrypted with AES Class Key 00. */ {0x83, 0x1C, 0xC7, 0x7F, 0xB8, 0xB2, 0x66, 0x16, 0xFC, 0x6B, 0x81, 0xBB, 0xF6, 0x05, 0x07, 0x49}, /* Zeroes encrypted with AES Class Key 01. */ @@ -83,6 +98,14 @@ static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; static const u8 retail_specific_aes_key_source[0x10] __attribute__((aligned(4))) = { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; +static const u8 secure_data_source[0x10] __attribute__((aligned(4))) = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const u8 secure_data_counters[1][0x10] __attribute__((aligned(4))) = { + {0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9} +}; +static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { + {0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E} +}; // from Package1ldr (or Secure_Monitor on 6.2.0+) static const u8 keyblob_mac_key_source[0x10] __attribute__((aligned(4))) = { @@ -102,6 +125,15 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. }; +static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { + {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. + {0xCC, 0x97, 0x4C, 0x46, 0x2A, 0x0C, 0xB0, 0xA6, 0xC9, 0xC0, 0xB7, 0xBE, 0x30, 0x2E, 0xC3, 0x68}, // 6.2.0. + {0x86, 0xBD, 0x1D, 0x76, 0x50, 0xDF, 0x6D, 0xFA, 0x2C, 0x7D, 0x33, 0x22, 0xAB, 0xF1, 0x82, 0x18}, // 7.0.0. + {0xA3, 0xB1, 0xE0, 0xA9, 0x58, 0xA2, 0x26, 0x7F, 0x40, 0xBF, 0x5B, 0xBB, 0x87, 0x33, 0x0B, 0x66}, // 8.1.0. + {0x82, 0x72, 0x91, 0x65, 0x40, 0x3B, 0x9D, 0x66, 0x60, 0xD0, 0x1B, 0x3D, 0x4D, 0xA5, 0x70, 0xE1}, // 9.0.0. + {0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE}, // 9.1.0. + {0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0. +}; static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ @@ -118,6 +150,8 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI // from ES static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; +static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { + 0xBE, 0xC0, 0xBC, 0x8E, 0x75, 0xA0, 0xF6, 0x0C, 0x4A, 0x56, 0x64, 0x02, 0x3E, 0xD4, 0x9C, 0xD5}; static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; @@ -139,6 +173,18 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ }; +static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { + {0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */ + {0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */ + {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */ + {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */ + {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */ + {0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */ + {0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */ + {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ + {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ +}; + // from SPL static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 765ac5a..387ebfc 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -70,13 +70,14 @@ static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { } // key functions -static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; -static void _save_key(const char *name, const void *data, u32 len, char *outbuf); -static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); -static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *new_device_key, const void *master_key); +static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; +static void _save_key(const char *name, const void *data, u32 len, char *outbuf); +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); +static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation); +static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision); // titlekey functions -static bool _test_key_pair(const void *E, const void *D, const void *N); +static bool _test_key_pair(const void *E, const void *D, const void *N); static ALWAYS_INLINE u8 *_find_tsec_fw(const u8 *pkg1) { const u32 tsec_fw_align = 0x100; @@ -122,11 +123,11 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { return pkg1; } -static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { +static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); // Relies on the Mariko KEK being properly set in slot 12 - se_aes_unwrap_key(8, 12, &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]); + se_aes_unwrap_key(8, 12, is_dev ? &mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]); se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); } @@ -143,23 +144,27 @@ static int _run_ams_keygen(key_derivation_ctx_t *keys) { return res; } -static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys) { +static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool is_dev) { if (!h_cfg.t210b01) { - se_aes_crypt_block_ecb(13, 0, keys->master_kek[KB_FIRMWARE_VERSION_MAX], master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620]); // mkek = unwrap(tsec_root, mkeks) - se_aes_key_set(8, keys->master_kek[KB_FIRMWARE_VERSION_MAX], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) - se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); + u32 tsec_root_key_slot = is_dev ? 11 : 13; + // Derive all master keys based on current root key + for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { + se_aes_crypt_block_ecb(tsec_root_key_slot, 0, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks) + se_aes_key_set(8, keys->master_kek[i + KB_FIRMWARE_VERSION_620], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) + se_aes_crypt_block_ecb(8, 0, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source); + } } // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); + se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); } se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); + se_aes_crypt_block_ecb(8, 0, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); if (_key_exists(keys->temp_key)) { - EPRINTF("Unable to derive master key."); + EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); memset(keys->master_key, 0, sizeof(keys->master_key)); } } @@ -230,33 +235,42 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { if (!(_key_exists(keys->device_key) || (key_generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { return; } - _get_device_key(8, keys->temp_key, key_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); - se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_sources[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_sources[0] + 0x10); + _generate_specific_aes_key(8, keys, &keys->bis_key[0], &bis_key_sources[0], key_generation); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_sources[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_sources[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_sources[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_sources[2] + 0x10); + se_aes_crypt_ecb(8, 0, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) + se_aes_crypt_ecb(8, 0, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2); memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); } -static void _derive_misc_keys(key_derivation_ctx_t *keys) { +static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x00, header_key_source + 0x00); - se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x10, header_key_source + 0x10); + se_aes_crypt_ecb(8, 0, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2); } +} +static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { - _get_device_key(8, keys->temp_key, 0, keys->device_key, keys->device_key_4x, keys->master_key[0]); + _get_device_key(8, keys, keys->temp_key, 0); _generate_kek(8, save_mac_kek_source, keys->temp_key, aes_kek_generation_source, NULL); se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); } + if (_key_exists(keys->master_key[0])) { + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(8, 0, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); + + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(8, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); + } +} + +static void _derive_master_key_per_generation_keys(key_derivation_ctx_t *keys) { for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) { if (!_key_exists(keys->master_key[i])) continue; @@ -268,19 +282,6 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys) { se_aes_crypt_block_ecb(8, 0, keys->package2_key[i], package2_key_source); se_aes_crypt_block_ecb(8, 0, keys->titlekek[i], titlekek_source); } - - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(keys->master_key[0])) { - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, keys->eticket_rsa_kek, eticket_rsa_kek_source); - - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); - } } static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { @@ -493,7 +494,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; - _get_device_key(7, temp_device_key, keypair_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); + _get_device_key(7, keys, temp_device_key, keypair_generation); _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL); se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source); memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key)); @@ -521,7 +522,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &rsa_keypair); - gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); + gfx_printf("\n%k Found %d titlekeys.\n\n", colors[(color_idx++) % 6], _titlekey_count); return true; } @@ -654,7 +655,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { free(text_buffer); } -static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time) { +static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { char *text_buffer = NULL; if (!sd_mount()) { EPRINTF("Unable to mount SD."); @@ -673,7 +674,11 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); SAVE_KEY_VAR(eticket_rsa_kek_personalized, keys->eticket_rsa_kek_personalized); - SAVE_KEY(eticket_rsa_kek_source); + if (is_dev) { + SAVE_KEY_VAR(eticket_rsa_kek_source, eticket_rsa_kek_source_dev); + } else { + SAVE_KEY(eticket_rsa_kek_source); + } SAVE_KEY(eticket_rsa_kekek_source); SAVE_KEY(header_kek_source); SAVE_KEY_VAR(header_key, keys->header_key); @@ -686,9 +691,14 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0); SAVE_KEY_FAMILY_VAR(keyblob_key, keys->keyblob_key, 0); - SAVE_KEY_FAMILY(keyblob_key_sources, 0); + SAVE_KEY_FAMILY_VAR(keyblob_key_source, keyblob_key_sources, 0); SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); + if (is_dev) { + SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources_dev, 5); + } else { + SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources, 5); + } SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); SAVE_KEY_FAMILY_VAR(master_key, keys->master_key, 0); @@ -727,18 +737,14 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl s_printf(root_key_name + 14, "%02x", root_key_ver); _save_key(root_key_name, keys->tsec_root_key, AES_128_KEY_SIZE, text_buffer); - s_printf(root_key_name + 14, "dev_%02x", root_key_ver); - _save_key(root_key_name, keys->tsec_root_key_dev, AES_128_KEY_SIZE, text_buffer); - - end_time = get_tmr_us(); - gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); - gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); + gfx_printf("\n%k Found %d %s keys.\n\n", colors[(color_idx++) % 6], _key_count, is_dev ? "dev" : "prod"); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/prod.keys"; - if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) + if (is_dev) { s_printf(&keyfile_path[11], "dev.keys"); + } FILINFO fno; if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { @@ -750,7 +756,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl _save_mariko_partial_keys(12, 4, true); } - if (_titlekey_count == 0) { + if (_titlekey_count == 0 || !titlekey_buffer) { free(text_buffer); return; } @@ -807,14 +813,17 @@ static void _derive_keys() { } free(pkg1); - key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; + bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; + + key_derivation_ctx_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; + key_derivation_ctx_t *keys = is_dev ? &dev_keys : &prod_keys; // Master key derivation if (h_cfg.t210b01) { - _derive_master_key_mariko(&keys); - _derive_master_keys_from_latest_key(&keys); + _derive_master_key_mariko(keys, is_dev); + _derive_master_keys_from_latest_key(keys, is_dev); } else { - int res = _run_ams_keygen(&keys); + int res = _run_ams_keygen(keys); if (res) { EPRINTF("Unable to run keygen."); return; @@ -822,33 +831,43 @@ static void _derive_keys() { u8 *aes_keys = (u8 *)calloc(0x1000, 1); se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); - memcpy(&keys.tsec_root_key_dev, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(&keys.tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(&keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&dev_keys.tsec_root_key, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(keys->tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&prod_keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); free(aes_keys); - _derive_master_keys_from_latest_key(&keys); - _derive_keyblob_keys(&keys); + _derive_master_keys_from_latest_key(&prod_keys, false); + _derive_master_keys_from_latest_key(&dev_keys, true); + _derive_keyblob_keys(keys); } TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); - _derive_bis_keys(&keys); + _derive_bis_keys(keys); TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - _derive_misc_keys(&keys); + _derive_misc_keys(keys, is_dev); + + _derive_non_unique_keys(&prod_keys, is_dev); + _derive_non_unique_keys(&dev_keys, is_dev); + _derive_master_key_per_generation_keys(&prod_keys); + _derive_master_key_per_generation_keys(&dev_keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; // BIS key for SYSTEM partition - if (_key_exists(keys.bis_key[2])) { - _derive_emmc_keys(&keys, titlekey_buffer); + if (_key_exists(keys->bis_key[2])) { + _derive_emmc_keys(keys, titlekey_buffer); } else { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); } - _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time); + end_time = get_tmr_us(); + gfx_printf("%kLockpick totally done in %d us\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); + _save_keys_to_sd(&prod_keys, titlekey_buffer, false); + _key_count = 0; + _save_keys_to_sd(&dev_keys, NULL, true); } void dump_keys() { @@ -908,9 +927,32 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons se_aes_unwrap_key(ks, ks, key_seed); } -static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const void *device_key, const void *new_device_key, const void *master_key) { +static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) { + se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE); + u8 *d = (u8 *)dst; + se_aes_crypt_ctr(6, d + 0x00, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + se_aes_crypt_ctr(6, d + 0x10, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + + // Apply tweak + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) { + d[AES_128_KEY_SIZE + i] ^= secure_data_tweaks[0][i]; + } +} + +static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation) { + if (fuse_read_bootrom_rev() >= 0x7F) { + _get_device_key(ks, keys, keys->temp_key, key_generation); + se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); + se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) + se_aes_crypt_ecb(ks, 0, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) + } else { + _get_secure_data(keys, out_key); + } +} + +static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision) { if (revision == KB_FIRMWARE_VERSION_100_200 && !h_cfg.t210b01) { - memcpy(out_device_key, device_key, AES_128_KEY_SIZE); + memcpy(out_device_key, keys->device_key, AES_128_KEY_SIZE); return; } @@ -920,10 +962,11 @@ static void _get_device_key(u32 ks, void *out_device_key, u32 revision, const vo revision = 0; } u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; - se_aes_key_set(ks, new_device_key, AES_128_KEY_SIZE); + se_aes_key_set(ks, keys->device_key_4x, AES_128_KEY_SIZE); se_aes_crypt_block_ecb(ks, 0, temp_key, device_master_key_source_sources[revision]); - se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, device_master_kek_sources[revision]); + se_aes_key_set(ks, keys->master_key[0], AES_128_KEY_SIZE); + const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[revision] : device_master_kek_sources_dev[revision]; + se_aes_unwrap_key(ks, ks, kek_source); se_aes_crypt_block_ecb(ks, 0, out_device_key, temp_key); } diff --git a/source/keys/keys.h b/source/keys/keys.h index 32d7fb6..d264851 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -109,8 +109,7 @@ typedef struct { package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], tsec_key[AES_128_KEY_SIZE], - tsec_root_key[AES_128_KEY_SIZE], - tsec_root_key_dev[AES_128_KEY_SIZE]; + tsec_root_key[AES_128_KEY_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; } key_derivation_ctx_t; From f2f3c5daf0e93478825468bb28cfa764813801ca Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 28 Aug 2021 14:10:33 -0600 Subject: [PATCH 119/166] Update to hekate bdk 5.6.0 --- bdk/display/di.c | 247 +++++++++---- bdk/display/di.h | 67 ++-- bdk/display/di.inl | 4 +- bdk/input/als.c | 146 +++++--- bdk/input/als.h | 20 +- bdk/input/touch.c | 2 +- bdk/input/touch.h | 1 + bdk/mem/mc.c | 7 +- bdk/mem/mc.h | 2 +- bdk/mem/sdram.c | 142 +++----- bdk/mem/sdram.h | 100 ++++-- bdk/mem/sdram_config.inl | 79 +++-- bdk/mem/sdram_config_lz.inl | 124 ------- bdk/mem/sdram_config_t210b01.inl | 589 ++++++++++++++++--------------- bdk/power/regulator_5v.c | 30 +- bdk/power/regulator_5v.h | 2 +- bdk/sec/se.c | 10 +- bdk/sec/se_t210.h | 3 + bdk/sec/tsec.c | 194 +++++++--- bdk/sec/tsec.h | 33 +- bdk/sec/tsec_t210.h | 1 - bdk/soc/fuse.c | 38 +- bdk/soc/fuse.h | 8 +- bdk/soc/hw_init.c | 26 +- bdk/storage/mmc.h | 105 +++--- bdk/storage/sdmmc.c | 58 ++- bdk/storage/sdmmc.h | 78 ++++ bdk/usb/usb_gadget_ums.c | 88 +++-- bdk/usb/usb_t210.h | 7 +- bdk/usb/usbd.c | 6 +- bdk/usb/usbd.h | 7 +- bdk/usb/xusbd.c | 264 +++++++++----- bdk/utils/types.h | 1 + bdk/utils/util.c | 23 +- bdk/utils/util.h | 5 +- source/config.c | 5 - source/config.h | 4 - source/hos/hos.h | 128 +------ source/hos/pkg2.c | 210 ----------- source/hos/pkg2.h | 109 ------ source/keys/keys.c | 83 ++--- source/main.c | 1 + source/storage/nx_emmc_bis.c | 6 +- 43 files changed, 1530 insertions(+), 1533 deletions(-) delete mode 100644 bdk/mem/sdram_config_lz.inl delete mode 100644 source/hos/pkg2.c delete mode 100644 source/hos/pkg2.h diff --git a/bdk/display/di.c b/bdk/display/di.c index 1c79823..ee4b45d 100644 --- a/bdk/display/di.c +++ b/bdk/display/di.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ extern volatile nyx_storage_t *nyx_str; static u32 _display_id = 0; +static bool nx_aula = false; static void _display_panel_and_hw_end(bool no_panel_deinit); @@ -91,7 +93,7 @@ int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled) // Wait for vblank before starting the transfer. DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. - while (DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT) + while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) ; } @@ -134,19 +136,22 @@ int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled) case DCS_2_BYTE_SHORT_RD_RES: memcpy(data, &fifo[2], 2); break; + case ACK_ERROR_RES: default: res = 1; break; } } + else + res = 1; // Disable host cmd packets during video and restore host control. if (video_enabled) { // Wait for vblank before reseting sync points. DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. - while (DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT) + while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) ; // Reset all states of syncpt block. @@ -181,7 +186,7 @@ void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) host_control = DSI(_DSIREG(DSI_HOST_CONTROL)); // Enable host transfer trigger. - DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_TX_TRIG_HOST; + DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control | DSI_HOST_CONTROL_TX_TRIG_HOST; switch (len) { @@ -216,8 +221,71 @@ void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled) DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; } +void display_dsi_vblank_write(u8 cmd, u32 len, void *data) +{ + u8 *fifo8; + u32 *fifo32; + + // Enable vblank interrupt. + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = DC_CMD_INT_FRAME_END_INT; + + // Use the 4th line to transmit the host cmd packet. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4); + + // Wait for vblank before starting the transfer. + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. + while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) + ; + + switch (len) + { + case 0: + DSI(_DSIREG(DSI_WR_DATA)) = (cmd << 8) | MIPI_DSI_DCS_SHORT_WRITE; + break; + + case 1: + DSI(_DSIREG(DSI_WR_DATA)) = ((cmd | (*(u8 *)data << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + + default: + fifo32 = calloc(DSI_STATUS_RX_FIFO_SIZE * 8, 4); + fifo8 = (u8 *)fifo32; + fifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE; + fifo8[4] = cmd; + memcpy(&fifo8[5], data, len); + len += 4 + 1; // Increase length by CMD/length word and DCS CMD. + for (u32 i = 0; i < (ALIGN(len, 4) / 4); i++) + DSI(_DSIREG(DSI_WR_DATA)) = fifo32[i]; + free(fifo32); + break; + } + + // Wait for vblank before reseting sync points. + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. + while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) + ; + + // Reset all states of syncpt block. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = DSI_INCR_SYNCPT_SOFT_RESET; + usleep(300); // Stabilization delay. + + // Clear syncpt block reset. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = 0; + usleep(300); // Stabilization delay. + + // Restore video mode and host control. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + + // Disable and clear vblank interrupt. + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = 0; + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; +} + void display_init() { + // Get Hardware type, as it's used in various DI functions. + nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA; + // Check if display is already initialized. if (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_DISP1)) _display_panel_and_hw_end(true); @@ -270,22 +338,31 @@ void display_init() PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; // PULL_DOWN | 1 PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN - // Set LCD +-5V pins mode and direction - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); + if (nx_aula) + { + // Configure LCD RST pin. + gpio_config(GPIO_PORT_V, GPIO_PIN_2, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_V, GPIO_PIN_2, GPIO_OUTPUT_ENABLE); + } + else + { + // Set LCD +-5V pins mode and direction + gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); - // Enable LCD power. - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // LCD +5V enable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // LCD -5V enable. - usleep(10000); + // Enable LCD power. + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // LCD +5V enable. + usleep(10000); + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // LCD -5V enable. + usleep(10000); - // Configure Backlight PWM/EN and LCD RST pins (BL PWM, BL EN, LCD RST). - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); + // Configure Backlight PWM/EN and LCD RST pins (BL PWM, BL EN, LCD RST). + gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - // Enable Backlight power. - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); + // Enable Backlight power. + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); + } // Power up supply regulator for display interface. MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0; @@ -336,35 +413,18 @@ void display_init() usleep(60000); // Setup DSI device takeover timeout. - DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; + DSI(_DSIREG(DSI_BTA_TIMING)) = nx_aula ? 0x40103 : 0x50204; -#if 0 // Get Display ID. - _display_id = 0xCCCCCC; // Set initial value. 4th byte cleared. - display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id, DSI_VIDEO_DISABLED); -#else - // Drain RX FIFO. - _display_dsi_read_rx_fifo(NULL); - - // Set reply size. - _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0); - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - // Request register read. - _display_dsi_send_cmd(MIPI_DSI_DCS_READ, MIPI_DCS_GET_DISPLAY_ID, 0); - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - // Transfer bus control to device for transmitting the reply. - DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; - _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); - - // Wait a bit for the reply. - usleep(5000); - - // MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 x u32. + _display_id = 0xCCCCCC; for (u32 i = 0; i < 3; i++) - _display_id = DSI(_DSIREG(DSI_RD_DATA)) & 0xFFFFFF; // Skip ack and msg type info and get the payload (display id). -#endif + { + if (!display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id, DSI_VIDEO_DISABLED)) + break; + + usleep(10000); + } + // Save raw Display ID to Nyx storage. nyx_str->info.disp_id = _display_id; @@ -374,9 +434,23 @@ void display_init() if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) _display_id = PANEL_JDI_XXX062M; + // For Aula ensure that we have a compatible panel id. + if (nx_aula && _display_id == 0xCCCC) + _display_id = PANEL_SAM_70_UNK; + // Initialize display panel. switch (_display_id) { + case PANEL_SAM_70_UNK: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xA0, 0); // Write 0 to 0xA0. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_SET_CONTROL_DISPLAY | (DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL << 8), 0); // Enable brightness control. + DSI(_DSIREG(DSI_WR_DATA)) = 0x339; // MIPI_DSI_DCS_LONG_WRITE: 3 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x000051; // MIPI_DCS_SET_BRIGHTNESS 0000: 0%. FF07: 100%. + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + case PANEL_JDI_XXX062M: exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); @@ -415,7 +489,7 @@ void display_init() _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); // Configure PLLD for DISP1. - plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 234 MHz (offset). + plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 234 MHz (offset, it's ddr btw, so normally div2). CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; if (tegra_t210) @@ -465,6 +539,9 @@ void display_init() void display_backlight_pwm_init() { + if (_display_id == PANEL_SAM_70_UNK) + return; + clock_enable_pwm(); PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. 29.5KHz is stock. @@ -478,20 +555,23 @@ void display_backlight(bool enable) gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO. } -void display_backlight_brightness(u32 brightness, u32 step_delay) +void display_dsi_backlight_brightness(u32 brightness) +{ + u16 bl_ctrl = byte_swap_16((u16)(brightness * 8)); + display_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl); +} + +void display_pwm_backlight_brightness(u32 brightness, u32 step_delay) { u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF; if (brightness == old_value) return; - if (brightness > 255) - brightness = 255; - if (old_value < brightness) { for (u32 i = old_value; i < brightness + 1; i++) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); usleep(step_delay); } } @@ -499,7 +579,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) { for (u32 i = old_value; i > brightness; i--) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); usleep(step_delay); } } @@ -507,6 +587,17 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; } +void display_backlight_brightness(u32 brightness, u32 step_delay) +{ + if (brightness > 255) + brightness = 255; + + if (_display_id != PANEL_SAM_70_UNK) + display_pwm_backlight_brightness(brightness, step_delay); + else + display_dsi_backlight_brightness(brightness); +} + u32 display_get_backlight_brightness() { return ((PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF); @@ -532,7 +623,9 @@ static void _display_panel_and_hw_end(bool no_panel_deinit) // De-initialize video controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17); exec_cfg((u32 *)DSI_BASE, _display_dsi_timing_deinit_config, 16); - usleep(10000); + + if (_display_id != PANEL_SAM_70_UNK) + usleep(10000); // De-initialize display panel. switch (_display_id) @@ -584,16 +677,23 @@ static void _display_panel_and_hw_end(bool no_panel_deinit) } // Blank - powerdown. - _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, 50000); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, + (_display_id == PANEL_SAM_70_UNK) ? 120000 : 50000); skip_panel_deinit: // Disable LCD power pins. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); // LCD Reset disable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); // LCD -5V disable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); // LCD +5V disable. - usleep(10000); + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); // LCD Reset disable. + + if (!nx_aula) // HOS uses panel id. + { + usleep(10000); + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); // LCD -5V disable. + usleep(10000); + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); // LCD +5V disable. + usleep(10000); + } + else + usleep(30000); // Aula Panel. // Disable Display Interface specific clocks. CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); @@ -606,9 +706,12 @@ skip_panel_deinit: DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; // Switch LCD PWM backlight pin to special function mode and enable PWM0 mode. - gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode. + if (!nx_aula) + { + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode. + } } void display_end() { _display_panel_and_hw_end(false); }; @@ -620,11 +723,18 @@ u16 display_get_decoded_panel_id() void display_set_decoded_panel_id(u32 id) { + // Get Hardware type, as it's used in various DI functions. + nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA; + // Decode Display ID. _display_id = ((id >> 8) & 0xFF00) | (id & 0xFF); if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) _display_id = PANEL_JDI_XXX062M; + + // For Aula ensure that we have a compatible panel id. + if (nx_aula && _display_id == 0xCCCC) + _display_id = PANEL_SAM_70_UNK; } void display_color_screen(u32 color) @@ -637,9 +747,12 @@ void display_color_screen(u32 color) DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - usleep(35000); + usleep(35000); // No need to wait on Aula. - display_backlight(true); + if (_display_id != PANEL_SAM_70_UNK) + display_backlight(true); + else + display_backlight_brightness(255, 0); } u32 *display_init_framebuffer_pitch() @@ -649,7 +762,7 @@ u32 *display_init_framebuffer_pitch() // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch, 32); - usleep(35000); + usleep(35000); // No need to wait on Aula. return (u32 *)IPL_FB_ADDRESS; } @@ -658,8 +771,7 @@ u32 *display_init_framebuffer_pitch_inv() { // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch_inv, 34); - - usleep(35000); + usleep(35000); // No need to wait on Aula. return (u32 *)NYX_FB_ADDRESS; } @@ -668,8 +780,7 @@ u32 *display_init_framebuffer_block() { // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_block, 34); - - usleep(35000); + usleep(35000); // No need to wait on Aula. return (u32 *)NYX_FB_ADDRESS; } diff --git a/bdk/display/di.h b/bdk/display/di.h index 7682bdb..9229a22 100644 --- a/bdk/display/di.h +++ b/bdk/display/di.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -547,17 +547,17 @@ #define MIPI_DCS_GET_DISPLAY_ID1 0xDA // GET_DISPLAY_ID Byte0, Module Manufacturer ID. #define MIPI_DCS_GET_DISPLAY_ID2 0xDB // GET_DISPLAY_ID Byte1, Module/Driver Version ID. #define MIPI_DCS_GET_DISPLAY_ID3 0xDC // GET_DISPLAY_ID Byte2, Module/Driver ID. -#define MIPI_DCS_GET_NUM_ERRORS 0x05 +#define MIPI_DCS_GET_NUM_ERRORS 0x05 // 1 byte. #define MIPI_DCS_GET_RED_CHANNEL 0x06 #define MIPI_DCS_GET_GREEN_CHANNEL 0x07 #define MIPI_DCS_GET_BLUE_CHANNEL 0x08 -#define MIPI_DCS_GET_DISPLAY_STATUS 0x09 -#define MIPI_DCS_GET_POWER_MODE 0x0A -#define MIPI_DCS_GET_ADDRESS_MODE 0x0B -#define MIPI_DCS_GET_PIXEL_FORMAT 0x0C -#define MIPI_DCS_GET_DISPLAY_MODE 0x0D -#define MIPI_DCS_GET_SIGNAL_MODE 0x0E -#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0F +#define MIPI_DCS_GET_DISPLAY_STATUS 0x09 // 4 bytes. +#define MIPI_DCS_GET_POWER_MODE 0x0A // 1 byte. 2: DISON, 3: NORON, 4: SLPOUT, 7: BSTON. +#define MIPI_DCS_GET_ADDRESS_MODE 0x0B // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR. +#define MIPI_DCS_GET_PIXEL_FORMAT 0x0C // 1 byte. 4-6: DPI. +#define MIPI_DCS_GET_DISPLAY_MODE 0x0D // 1 byte. 0-2: GCS, 3: ALLPOFF, 4: ALLPON, 5: INVON. +#define MIPI_DCS_GET_SIGNAL_MODE 0x0E // 1 byte. 0: EODSI, 2: DEON, 3: PCLKON, 4: VSON, 5: HSON, 7: TEON. +#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0F // 1 byte. 6: FUNDT, 7: REGLD. #define MIPI_DCS_ENTER_SLEEP_MODE 0x10 #define MIPI_DCS_EXIT_SLEEP_MODE 0x11 #define MIPI_DCS_ENTER_PARTIAL_MODE 0x12 @@ -567,7 +567,7 @@ #define MIPI_DCS_ALL_PIXELS_OFF 0x22 #define MIPI_DCS_ALL_PIXELS_ON 0x23 #define MIPI_DCS_SET_CONTRAST 0x25 // VCON in 40mV steps. 7-bit integer. -#define MIPI_DCS_SET_GAMMA_CURVE 0x26 +#define MIPI_DCS_SET_GAMMA_CURVE 0x26 // 1 byte. 0-7: GC. #define MIPI_DCS_SET_DISPLAY_OFF 0x28 #define MIPI_DCS_SET_DISPLAY_ON 0x29 #define MIPI_DCS_SET_COLUMN_ADDRESS 0x2A @@ -580,11 +580,11 @@ #define MIPI_DCS_SET_SCROLL_AREA 0x33 #define MIPI_DCS_SET_TEAR_OFF 0x34 #define MIPI_DCS_SET_TEAR_ON 0x35 -#define MIPI_DCS_SET_ADDRESS_MODE 0x36 +#define MIPI_DCS_SET_ADDRESS_MODE 0x36 // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR. #define MIPI_DCS_SET_SCROLL_START 0x37 #define MIPI_DCS_EXIT_IDLE_MODE 0x38 #define MIPI_DCS_ENTER_IDLE_MODE 0x39 -#define MIPI_DCS_SET_PIXEL_FORMAT 0x3A +#define MIPI_DCS_SET_PIXEL_FORMAT 0x3A // 1 byte. 4-6: DPI. #define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3C #define MIPI_DCS_READ_MEMORY_CONTINUE 0x3E #define MIPI_DCS_GET_3D_CONTROL 0x3F @@ -593,26 +593,34 @@ #define MIPI_DCS_GET_SCANLINE 0x45 #define MIPI_DCS_SET_TEAR_SCANLINE_WIDTH 0x46 #define MIPI_DCS_GET_SCANLINE_WIDTH 0x47 -#define MIPI_DCS_SET_BRIGHTNESS 0x51 // DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL. -#define MIPI_DCS_GET_BRIGHTNESS 0x52 -#define MIPI_DCS_SET_CONTROL_DISPLAY 0x53 -#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54 -#define MIPI_DCS_SET_CABC_VALUE 0x55 -#define MIPI_DCS_GET_CABC_VALUE 0x56 -#define MIPI_DCS_SET_CABC_MIN_BRI 0x5E -#define MIPI_DCS_GET_CABC_MIN_BRI 0x5F +#define MIPI_DCS_SET_BRIGHTNESS 0x51 // DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL. 1 byte. 0-7: DBV. +#define MIPI_DCS_GET_BRIGHTNESS 0x52 // 1 byte. 0-7: DBV. +#define MIPI_DCS_SET_CONTROL_DISPLAY 0x53 // 1 byte. 2: BL, 3: DD, 5: BCTRL. +#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54 // 1 byte. 2: BL, 3: DD, 5: BCTRL. +#define MIPI_DCS_SET_CABC_VALUE 0x55 // 1 byte. 0-32: C, 4-7: C. +#define MIPI_DCS_GET_CABC_VALUE 0x56 // 1 byte. 0-32: C, 4-7: C. +#define MIPI_DCS_SET_CABC_MIN_BRI 0x5E // 1 byte. 0-7: CMB. +#define MIPI_DCS_GET_CABC_MIN_BRI 0x5F // 1 byte. 0-7: CMB. +#define MIPI_DCS_GET_AUTO_BRI_DIAG_RES 0x68 // 1 byte. 6-7: D. #define MIPI_DCS_READ_DDB_START 0xA1 -#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 +#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 // 0x100 size. /*! MIPI DCS Panel Private CMDs. */ #define MIPI_DCS_PRIV_UNK_A0 0xA0 #define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1 -#define MIPI_DCS_PRIV_SET_EXTC 0xB9 +#define MIPI_DCS_PRIV_SET_EXTC 0xB9 // Enable extended commands. #define MIPI_DCS_PRIV_UNK_BD 0xBD #define MIPI_DCS_PRIV_UNK_D5 0xD5 #define MIPI_DCS_PRIV_UNK_D6 0xD6 #define MIPI_DCS_PRIV_UNK_D8 0xD8 #define MIPI_DCS_PRIV_UNK_D9 0xD9 +#define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP. +#define MIPI_DCS_PRIV_SET_EXTC_CMD_REG 0xFF // EXTC Command Set enable register. 5 bytes. Pass: FF 98 06 04, PAGE. + +/*! MIPI DCS Panel Private CMDs PAGE 1. */ +#define MIPI_DCS_PRIV_GET_DISPLAY_ID4 0x00 +#define MIPI_DCS_PRIV_GET_DISPLAY_ID5 0x01 +#define MIPI_DCS_PRIV_GET_DISPLAY_ID6 0x02 /*! MIPI DCS CMD Defines. */ #define DCS_POWER_MODE_DISPLAY_ON BIT(2) @@ -655,11 +663,15 @@ * [20] 98 [0F]: InnoLux P062CCA-??? [UNCONFIRMED MODEL REV] * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002) + * [30] XX [0F]: AUO A062TAN03 (59.06A33.003) [UNCONFIRMED ID] * * 5.5" panels for Hoag skus: * [20] 94 [10]: InnoLux 2J055IA-27A (Rev B1) - * [30] XX [10]: AUO A055TAN01 (59.05A30.001) [UNCONFIRMED ID] + * [30] 93 [10]: AUO A055TAN01 (59.05A30.001) * [40] XX [10]: Vendor 40 [UNCONFIRMED ID] + * + * 7.0" OLED panels for Aula skus: + * [50] XX [20]: Samsung AMS700XXXX [UNCONFIRMED ID and MODEL] */ /* Display ID Decoding: @@ -672,13 +684,13 @@ * 10h: Japan Display Inc. * 20h: InnoLux Corporation * 30h: AU Optronics - * 40h: Unknown1 - * 50h: Unknown2 (OLED? Samsung? LG?) + * 40h: Unknown0 + * 50h: Samsung * * Boards, Panel Size: * 0Fh: Icosa/Iowa, 6.2" * 10h: Hoag, 5.5" - * 20h: Unknown, x.x" + * 20h: Aula, 7.0" */ enum @@ -690,7 +702,8 @@ enum PANEL_AUO_A062TAN01 = 0x0F30, PANEL_INL_2J055IA_27A = 0x1020, PANEL_AUO_A055TAN01 = 0x1030, - PANEL_V40_55_UNK = 0x1040 + PANEL_V40_55_UNK = 0x1040, + PANEL_SAM_70_UNK = 0x2050 }; void display_init(); diff --git a/bdk/display/di.inl b/bdk/display/di.inl index f98c5c7..c1e5d84 100644 --- a/bdk/display/di.inl +++ b/bdk/display/di.inl @@ -200,10 +200,10 @@ static const cfg_op_t _display_dsi_init_config_part6[14] = { //DSI panel config. static const cfg_op_t _display_init_config_jdi[43] = { - {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x0439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. + {DSI_WR_DATA, 0xBD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes. {DSI_WR_DATA, 0xAAAAAAD8}, // Register: 0xD8. diff --git a/bdk/input/als.c b/bdk/input/als.c index 918661b..be55426 100644 --- a/bdk/input/als.c +++ b/bdk/input/als.c @@ -23,79 +23,117 @@ #include #include -#define HOS_GAIN BH1730_GAIN_64X -#define HOS_ITIME 38 +#define BH1730_DEFAULT_GAIN BH1730_GAIN_64X +#define BH1730_DEFAULT_ICYCLE 38 -void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime) +#define BH1730_INTERNAL_CLOCK_NS 2800 +#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */ +#define BH1730_ITIME_CYCLE_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */ + +#define BH1730_DEFAULT_ITIME_MS 100 + +#define BH1730_LUX_MULTIPLIER 3600 +#define BH1730_LUX_MULTIPLIER_AULA 1410 + +#define BH1730_LUX_MAX 100000 + +typedef struct _opt_win_cal_t { - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime)); + u32 rc; + u32 cv; + u32 ci; +} opt_win_cal_t; - als_val->gain = gain; - als_val->itime = itime; +// Nintendo Switch Icosa/Iowa Optical Window calibration. +const opt_win_cal_t opt_win_cal_default[] = { + { 500, 5002, 7502 }, + { 754, 2250, 2000 }, + { 1029, 1999, 1667 }, + { 1373, 884, 583 }, + { 1879, 309, 165 } +}; + +// Nintendo Switch Aula Optical Window calibration. +const opt_win_cal_t opt_win_cal_aula[] = { + { 231, 9697, 30300 }, + { 993, 3333, 2778 }, + { 1478, 1621, 1053 }, + { 7500, 81, 10 } +}; + +const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 }; + +void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle) +{ + if (gain > BH1730_GAIN_128X) + gain = BH1730_GAIN_128X; + + if (!cycle) + cycle = 1; + else if (cycle > 255) + cycle = 255; + + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle)); + + als_ctxt->gain = gain; + als_ctxt->cycle = cycle; } -void get_als_lux(als_table_t *als_val) +void get_als_lux(als_ctxt_t *als_ctxt) { u32 data[2]; - float pre_gain_lux; - float visible_light; - float ir_light; - float light_ratio; + u32 visible_light; + u32 ir_light; + u64 lux = 0; + u32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle; - u8 adc_ready = 0; - u8 retries = 100; - - const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 }; - const float als_norm_res = 100.0; - const float als_multiplier = 3.6; - const float als_tint = 2.7; - - // Wait for ADC to prepare new data. - while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries) - { - retries--; - adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG)); - } - - // Get visible and ir light raw data. + // Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter. data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); - als_val->over_limit = data[0] > 65534 || data[1] > 65534; - als_val->vi_light = data[0]; - als_val->ir_light = data[1]; + visible_light = data[0]; + ir_light = data[1]; - if (!data[0] || !retries) + als_ctxt->over_limit = visible_light > 65534 || ir_light > 65534; + als_ctxt->vi_light = visible_light; + als_ctxt->ir_light = ir_light; + + if (!visible_light) { - als_val->lux = 0.0; + als_ctxt->lux = 0; return; } - visible_light = (float)data[0]; - ir_light = (float)data[1]; - light_ratio = (float)data[1] / (float)data[0]; + // Set calibration parameters. + u32 lux_multiplier = BH1730_LUX_MULTIPLIER; + u32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default); + const opt_win_cal_t *opt_win_cal = opt_win_cal_default; - // The following are specific to the light filter Switch uses. - if (light_ratio < 0.5) - pre_gain_lux = visible_light * 5.002 - ir_light * 7.502; - else if (light_ratio < 0.754) - pre_gain_lux = visible_light * 2.250 - ir_light * 2.000; - else if (light_ratio < 1.029) - pre_gain_lux = visible_light * 1.999 - ir_light * 1.667; - else if (light_ratio < 1.373) - pre_gain_lux = visible_light * 0.884 - ir_light * 0.583; - else if (light_ratio < 1.879) - pre_gain_lux = visible_light * 0.309 - ir_light * 0.165; - else pre_gain_lux = 0.0; + // Apply optical window calibration coefficients. + for (u32 i = 0; i < opt_win_cal_count; i++) + { + if (1000 * ir_light / visible_light < opt_win_cal[i].rc) + { + lux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]); + break; + } + } - als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier; + lux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier; + lux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us; + lux /= 1000; + + if (lux > BH1730_LUX_MAX) + lux = BH1730_LUX_MAX; + + als_ctxt->lux = lux; } -u8 als_init(als_table_t *als_val) +u8 als_power_on(als_ctxt_t *als_ctxt) { // Enable power to ALS IC. max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); @@ -109,12 +147,10 @@ u8 als_init(als_table_t *als_val) // Initialize ALS. u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME)); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); - als_val->gain = HOS_GAIN; - als_val->itime = HOS_ITIME; + set_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE); + + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); return id; } diff --git a/bdk/input/als.h b/bdk/input/als.h index 09adcb6..0ce0956 100644 --- a/bdk/input/als.h +++ b/bdk/input/als.h @@ -48,18 +48,18 @@ #define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg)) #define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd)) -typedef struct _als_table_t +typedef struct _als_ctxt_t { - float lux; + u32 lux; bool over_limit; - u32 vi_light; - u32 ir_light; - u8 gain; - u8 itime; -} als_table_t; + u32 vi_light; + u32 ir_light; + u8 gain; + u8 cycle; +} als_ctxt_t; -void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime); -void get_als_lux(als_table_t *als_val); -u8 als_init(als_table_t *als_val); +void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle); +void get_als_lux(als_ctxt_t *als_ctxt); +u8 als_power_on(als_ctxt_t *als_ctxt); #endif /* __ALS_H_ */ diff --git a/bdk/input/touch.c b/bdk/input/touch.c index 17d31b3..2aba0e4 100644 --- a/bdk/input/touch.c +++ b/bdk/input/touch.c @@ -39,7 +39,7 @@ static touch_panel_info_t _panels[] = { 1, 0, 1, 1, "GiS GGM6 B2X" }, { 2, 0, 0, 0, "NISSHA NBF-K9A" }, { 3, 1, 0, 0, "GiS 5.5\"" }, - { 4, 0, 0, 1, "Unknown" }, + { 4, 0, 0, 1, "Unknown_001" }, { -1, 1, 0, 1, "GiS VA 6.2\"" } }; diff --git a/bdk/input/touch.h b/bdk/input/touch.h index 3345faa..871659e 100644 --- a/bdk/input/touch.h +++ b/bdk/input/touch.h @@ -53,6 +53,7 @@ #define STMFTS_RW_FRAMEBUFFER_REG 0xD0 #define STMFTS_SAVE_CX_TUNING 0xFC +#define STMFTS_DETECTION_CONFIG 0xB0 #define STMFTS_REQU_COMP_DATA 0xB8 #define STMFTS_VENDOR 0xCF #define STMFTS_FLASH_UNLOCK 0xF7 diff --git a/bdk/mem/mc.c b/bdk/mem/mc.c index c695987..d577bd7 100644 --- a/bdk/mem/mc.c +++ b/bdk/mem/mc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 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, @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -124,13 +125,13 @@ void mc_config_carveout() MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F; } -void mc_enable_ahb_redirect() +void mc_enable_ahb_redirect(bool full_aperture) { // Enable ARC_CLK_OVR_ON. CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000; //MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE; MC(MC_IRAM_BOM) = 0x40000000; - MC(MC_IRAM_TOM) = 0x4003F000; + MC(MC_IRAM_TOM) = full_aperture ? DRAM_START : 0x4003F000; } void mc_disable_ahb_redirect() diff --git a/bdk/mem/mc.h b/bdk/mem/mc.h index 1a9bc83..d873c7d 100644 --- a/bdk/mem/mc.h +++ b/bdk/mem/mc.h @@ -23,7 +23,7 @@ void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); void mc_config_carveout(); void mc_config_carveout_finalize(); -void mc_enable_ahb_redirect(); +void mc_enable_ahb_redirect(bool full_aperture); void mc_disable_ahb_redirect(); void mc_enable(); diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c index b119f46..0f2ce3e 100644 --- a/bdk/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -36,22 +36,46 @@ #define CONFIG_SDRAM_KEEP_ALIVE -//#define CONFIG_SDRAM_COMPRESS_CFG - typedef struct _sdram_vendor_patch_t { u32 val; - u32 addr:10; - u32 dramid:22; + u32 offset:16; + u32 dramcf:16; } sdram_vendor_patch_t; -#ifdef CONFIG_SDRAM_COMPRESS_CFG - #include - #include "sdram_config_lz.inl" -#else - #include "sdram_config.inl" -#endif +static const u8 dram_encoding_t210b01[] = { + LPDDR4X_UNUSED, + LPDDR4X_UNUSED, + LPDDR4X_UNUSED, + LPDDR4X_4GB_HYNIX_1Y_A, + LPDDR4X_UNUSED, + LPDDR4X_4GB_HYNIX_1Y_A, + LPDDR4X_4GB_HYNIX_1Y_A, + LPDDR4X_4GB_SAMSUNG_X1X2, + LPDDR4X_NO_PATCH, + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, + LPDDR4X_NO_PATCH, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046, + LPDDR4X_NO_PATCH, + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, + LPDDR4X_NO_PATCH, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046, + LPDDR4X_4GB_SAMSUNG_Y, + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, + LPDDR4X_4GB_SAMSUNG_1Y_Y, + LPDDR4X_8GB_SAMSUNG_1Y_Y, + LPDDR4X_UNUSED, // Removed. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, + LPDDR4X_4GB_MICRON_1Y_A, + LPDDR4X_4GB_MICRON_1Y_A, + LPDDR4X_4GB_MICRON_1Y_A, + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, +}; +#include "sdram_config.inl" #include "sdram_config_t210b01.inl" static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) @@ -1350,57 +1374,21 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params) SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); } -#ifndef CONFIG_SDRAM_COMPRESS_CFG -static void _sdram_patch_model_params_t210(u32 dramid, u32 *params) -{ - for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210); i++) - if (sdram_cfg_vendor_patches_t210[i].dramid & DRAM_ID(dramid)) - params[sdram_cfg_vendor_patches_t210[i].addr] = sdram_cfg_vendor_patches_t210[i].val; -} -#endif - -static void _sdram_patch_model_params_t210b01(u32 dramid, u32 *params) -{ - for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210b01); i++) - if (sdram_cfg_vendor_patches_t210b01[i].dramid & DRAM_ID2(dramid)) - params[sdram_cfg_vendor_patches_t210b01[i].addr] = sdram_cfg_vendor_patches_t210b01[i].val; -} - static void *_sdram_get_params_t210() { // Check if id is proper. u32 dramid = fuse_read_dramid(false); -#ifdef CONFIG_SDRAM_COMPRESS_CFG + // Copy base parameters. + u32 *params = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(params, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t210_t)); - u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; - LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); - return (void *)&buf[sizeof(sdram_params_t210_t) * dramid]; + // Patch parameters if needed. + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210); i++) + if (sdram_cfg_vendor_patches_t210[i].dramcf & DRAM_ID(dramid)) + params[sdram_cfg_vendor_patches_t210[i].offset] = sdram_cfg_vendor_patches_t210[i].val; -#else - - u32 *buf = (u32 *)SDRAM_PARAMS_ADDR; - memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t210_t)); - - switch (dramid) - { - case LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH: - case LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT: - break; - - case LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE: - case LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH: -#ifdef CONFIG_SDRAM_COPPER_SUPPORT - case LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH: - case LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE: - case LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT: -#endif - _sdram_patch_model_params_t210(dramid, (u32 *)buf); - break; - } - return (void *)buf; - -#endif + return (void *)params; } void *sdram_get_params_t210b01() @@ -1408,38 +1396,20 @@ void *sdram_get_params_t210b01() // Check if id is proper. u32 dramid = fuse_read_dramid(false); - u32 *buf = (u32 *)SDRAM_PARAMS_ADDR; - memcpy(buf, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t)); + // Copy base parameters. + u32 *params = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(params, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t)); - switch (dramid) - { - case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: - case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME: - case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: - case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME: - break; + // Patch parameters if needed. + u8 dram_code = dram_encoding_t210b01[dramid]; + if (!dram_code) + return (void *)params; - case LPDDR4X_IOWA_4GB_SAMSUNG_X1X2: - case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: - case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT: - case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: - case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT: - case LPDDR4X_IOWA_4GB_SAMSUNG_Y: - case LPDDR4X_IOWA_4GB_SAMSUNG_1Y_X: - case LPDDR4X_IOWA_8GB_SAMSUNG_1Y_X: - case LPDDR4X_HOAG_4GB_SAMSUNG_1Y_X: - case LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y: - case LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y: - case LPDDR4X_AULA_4GB_SAMSUNG_1Y_A: - case LPDDR4X_AULA_8GB_SAMSUNG_1Y_X: - case LPDDR4X_AULA_4GB_SAMSUNG_1Y_X: - case LPDDR4X_IOWA_4GB_MICRON_1Y_A: - case LPDDR4X_HOAG_4GB_MICRON_1Y_A: - case LPDDR4X_AULA_4GB_MICRON_1Y_A: - _sdram_patch_model_params_t210b01(dramid, (u32 *)buf); - break; - } - return (void *)buf; + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210b01); i++) + if (sdram_cfg_vendor_patches_t210b01[i].dramcf == dram_code) + params[sdram_cfg_vendor_patches_t210b01[i].offset] = sdram_cfg_vendor_patches_t210b01[i].val; + + return (void *)params; } /* @@ -1485,7 +1455,7 @@ static void _sdram_init_t210() const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210(); // Set DRAM voltage. - max7762x_regulator_set_voltage(REGULATOR_SD1, 1100000); + max7762x_regulator_set_voltage(REGULATOR_SD1, 1100000); // HOS uses 1.125V // VDDP Select. PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h index 8455862..90e688d 100644 --- a/bdk/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2020 CTCaer + * Copyright (c) 2020-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,20 +23,26 @@ /* * Tegra X1/X1+ EMC/DRAM Bandwidth Chart: * - * 40.8 MHz: 0.61 GiB/s - * 68.0 MHz: 1.01 GiB/s - * 102.0 MHz: 1.52 GiB/s - * 204.0 MHz: 3.04 GiB/s <-- Tegra X1/X1+ Init/SC7 Frequency - * 408.0 MHz: 6.08 GiB/s - * 665.6 MHz: 9.92 GiB/s - * 800.0 MHz: 11.92 GiB/s <-- Tegra X1/X1+ Nvidia OS Boot Frequency - * 1065.6 MHz: 15.89 GiB/s - * 1331.2 MHz: 19.84 GiB/s - * 1600.0 MHz: 23.84 GiB/s <-- Tegra X1 Official Max Frequency - * 1862.4 MHz: 27.75 GiB/s <-- Tegra X1+ Official Max Frequency - * 2131.2 MHz: 31.76 GiB/s + * Note: BWbits T210 = Hz x ddr x bus width x channels = Hz x 2 x 32 x 2. + * BWbits T210B01 = Hz x ddr x bus width x channels = Hz x 2 x 64 x 2. + * Both assume that both sub-partitions are used and thus reaching max + * bandwidth per channel. (T210: 2x16-bit, T210B01: 2x32-bit). + * Retail Mariko use one sub-partition, in order to meet Erista perf. + * + * T210 T210B01 + * 40.8 MHz: 0.61 1.22 GiB/s + * 68.0 MHz: 1.01 2.02 GiB/s + * 102.0 MHz: 1.52 3.04 GiB/s + * 204.0 MHz: 3.04 6.08 GiB/s <-- Tegra X1/X1+ Init/SC7 Frequency + * 408.0 MHz: 6.08 12.16 GiB/s + * 665.6 MHz: 9.92 19.84 GiB/s + * 800.0 MHz: 11.92 23.84 GiB/s <-- Tegra X1/X1+ Nvidia OS Boot Frequency + * 1065.6 MHz: 15.89 31.78 GiB/s + * 1331.2 MHz: 19.84 39.68 GiB/s + * 1600.0 MHz: 23.84 47.68 GiB/s <-- Tegra X1/X1+ HOS Max Frequency + * 1862.4 MHz: 27.75 55.50 GiB/s <-- Tegra X1 Official Max Frequency + * 2131.2 MHz: 31.76 63.52 GiB/s <-- Tegra X1+ Official Max Frequency * - * Note: BWbits = Hz x bus width x channels = Hz x 64 x 2. */ enum sdram_ids_erista @@ -45,45 +51,73 @@ enum sdram_ids_erista LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, - LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, // Changed to AULA Hynix 4GB 1Y-A. + LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, // Changed to Iowa Hynix 4GB 1Y-A. LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, - LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 5, - LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT = 6, + LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 5, // Changed to Hoag Hynix 4GB 1Y-A. + LPDDR4_COPPER_4GB_MICRON_MT53B512M32D2NP_062_WT = 6, // Changed to Aula Hynix 4GB 1Y-A. }; enum sdram_ids_mariko { + // LPDDR4X 4266Mbps. + LPDDR4X_IOWA_4GB_HYNIX_1Y_A = 3, // Replaced from Copper. + LPDDR4X_HOAG_4GB_HYNIX_1Y_A = 5, // Replaced from Copper. + LPDDR4X_AULA_4GB_HYNIX_1Y_A = 6, // Replaced from Copper. + // LPDDR4X 3733Mbps. LPDDR4X_IOWA_4GB_SAMSUNG_X1X2 = 7, - LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, - LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, - LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, - LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT = 11, // 4266Mbps. + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, // Die-M. + LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, // Die-M. + LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, // Die-M. + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT = 11, // 4266Mbps. WT:E. Die-E. - LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, - LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, - LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, - LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT = 15, // 4266Mbps. + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, // Die-M. + LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, // Die-M. + LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, // Die-M. + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT = 15, // 4266Mbps. WT:E. Die-E. - // LPDDR4X 4266Mbps? + // LPDDR4X 4266Mbps. LPDDR4X_IOWA_4GB_SAMSUNG_Y = 16, - LPDDR4X_IOWA_4GB_SAMSUNG_1Y_X = 17, - LPDDR4X_IOWA_8GB_SAMSUNG_1Y_X = 18, - LPDDR4X_HOAG_4GB_SAMSUNG_1Y_X = 19, + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17, // Die-A. + LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18, // Die-A. + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19, // Die-A. LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y = 20, LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y = 21, - LPDDR4X_AULA_4GB_SAMSUNG_1Y_A = 22, + // LPDDR4X_AULA_4GB_SAMSUNG_1Y_A = 22, // Unused. - LPDDR4X_AULA_8GB_SAMSUNG_1Y_X = 23, - LPDDR4X_AULA_4GB_SAMSUNG_1Y_X = 24, + LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. + LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. LPDDR4X_IOWA_4GB_MICRON_1Y_A = 25, LPDDR4X_HOAG_4GB_MICRON_1Y_A = 26, - LPDDR4X_AULA_4GB_MICRON_1Y_A = 27 + LPDDR4X_AULA_4GB_MICRON_1Y_A = 27, + + LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, // Die-A. +}; + +enum sdram_codes_mariko +{ + LPDDR4X_NO_PATCH = 0, + LPDDR4X_UNUSED = 0, + + // LPDDR4X_4GB_SAMSUNG_K4U6E3S4AM_MGCJ DRAM IDs: 08, 12. + // LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLHR_NME DRAM IDs: 10, 14. + + LPDDR4X_4GB_SAMSUNG_X1X2 = 1, // DRAM IDs: 07. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 2, // DRAM IDs: 09, 13. + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 = 3, // DRAM IDs: 11, 15. + LPDDR4X_4GB_SAMSUNG_Y = 4, // DRAM IDs: 16. + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 5, // DRAM IDs: 17, 19, 24. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 6, // DRAM IDs: 18, 23, 28. + LPDDR4X_4GB_SAMSUNG_1Y_Y = 7, // DRAM IDs: 20. + LPDDR4X_8GB_SAMSUNG_1Y_Y = 8, // DRAM IDs: 21. + //LPDDR4X_4GB_SAMSUNG_1Y_A = 9, // DRAM IDs: 22. Unused. + LPDDR4X_4GB_MICRON_1Y_A = 10, // DRAM IDs: 25, 26, 27. + LPDDR4X_4GB_HYNIX_1Y_A = 11, // DRAM IDs: 03, 05, 06. }; void sdram_init(); diff --git a/bdk/mem/sdram_config.inl b/bdk/mem/sdram_config.inl index 97c723a..4548981 100644 --- a/bdk/mem/sdram_config.inl +++ b/bdk/mem/sdram_config.inl @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2020 CTCaer + * Copyright (c) 2020-2021 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, @@ -646,46 +646,51 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = { // Hynix timing config. - { 0x0000000D, 67, DRAM_ID(1) | DRAM_ID(5) }, // emc_r2w. - { 0x00000001, 91, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_extra. - { 0x80000000, 92, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_width. - { 0x00000210, 317, DRAM_ID(1) | DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. - { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. + { 0x0000000D, 0x10C / 4, DRAM_ID(1) }, // emc_r2w. + { 0x00000001, 0x16C / 4, DRAM_ID(1) }, // emc_puterm_extra. + { 0x80000000, 0x170 / 4, DRAM_ID(1) }, // emc_puterm_width. + { 0x00000210, 0x4F4 / 4, DRAM_ID(1) }, // emc_pmacro_data_rx_term_mode. + { 0x00000005, 0x5C0 / 4, DRAM_ID(1) }, // mc_emem_arb_timing_r2w. // Samsung 6GB density config. - { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB Rank 0 density. - { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB Rank 1 density. - { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. + { 0x000C0302, 0x56C / 4, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB Rank 0 density. + { 0x000C0302, 0x570 / 4, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB Rank 1 density. + { 0x00001800, 0x584 / 4, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. #ifdef CONFIG_SDRAM_COPPER_SUPPORT // Copper prototype Samsung/Hynix/Micron timing configs. - { 0x0000003A, 59, DRAM_ID(6) }, // emc_rfc. Auto refresh. - { 0x0000001D, 60, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. - { 0x00000012, 108, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. - { 0x0000003B, 112, DRAM_ID(6) }, // emc_txsr. - { 0x0000003B, 113, DRAM_ID(6) }, // emc_txsr_dll. - { 0x00000003, 119, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_tclkstable. - { 0x00120015, 205, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x00160012, 206, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. - { 0x00120015, 211, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x00160012, 212, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. - { 0x002F0032, 213, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x00310032, 214, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00360034, 215, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x0033002F, 216, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. - { 0x00000006, 217, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x002F0032, 219, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x00310032, 220, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00360034, 221, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x0033002F, 222, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. - { 0x00000006, 223, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x00150015, 233, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_0. - { 0x00120012, 235, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_2. - { 0x00160016, 236, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_3. - { 0x00000015, 237, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4. - { 0x00000012, 295, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2. - { 0x00000012, 296, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3. - { 0x00000007, 370, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh. - { 0x72A30504, 373, DRAM_ID(6) }, // mc_emem_arb_misc0. + { 0x0000003A, 0xEC / 4, DRAM_ID(6) }, // emc_rfc. Auto refresh. + { 0x0000001D, 0xF0 / 4, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. + { 0x0000000D, 0x10C / 4, DRAM_ID(5) }, // emc_r2w. + { 0x00000001, 0x16C / 4, DRAM_ID(5) }, // emc_puterm_extra. + { 0x80000000, 0x170 / 4, DRAM_ID(5) }, // emc_puterm_width. + { 0x00000012, 0x1B0 / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. + { 0x0000003B, 0x1C0 / 4, DRAM_ID(6) }, // emc_txsr. + { 0x0000003B, 0x1C4 / 4, DRAM_ID(6) }, // emc_txsr_dll. + { 0x00000003, 0x1DC / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_tclkstable. + { 0x00120015, 0x334 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x00160012, 0x338 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x00120015, 0x34C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00160012, 0x350 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x002F0032, 0x354 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00310032, 0x358 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00360034, 0x35C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0033002F, 0x360 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x00000006, 0x364 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x002F0032, 0x36C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00310032, 0x370 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00360034, 0x374 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0033002F, 0x378 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x00000006, 0x37C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00150015, 0x3A4 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_0. + { 0x00120012, 0x3AC / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_2. + { 0x00160016, 0x3B0 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000015, 0x3B4 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4. + { 0x00000012, 0x49C / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2. + { 0x00000012, 0x4A0 / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3. + { 0x00000210, 0x4F4 / 4, DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. + { 0x00000005, 0x5C0 / 4, DRAM_ID(5) }, // mc_emem_arb_timing_r2w. + { 0x00000007, 0x5C8 / 4, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh. + { 0x72A30504, 0x5D4 / 4, DRAM_ID(6) }, // mc_emem_arb_misc0. #endif }; diff --git a/bdk/mem/sdram_config_lz.inl b/bdk/mem/sdram_config_lz.inl deleted file mode 100644 index 832b5b4..0000000 --- a/bdk/mem/sdram_config_lz.inl +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -static const u8 _dram_cfg_lz[1262] = { - 0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, - 0x00, 0x2C, 0x17, 0x04, 0x09, 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, - 0x17, 0x10, 0x10, 0x00, 0x00, 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0xB4, 0x01, 0x70, 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, - 0x70, 0x17, 0x10, 0x24, 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, - 0x00, 0x00, 0x00, 0x17, 0x04, 0x04, 0x17, 0x09, 0x18, 0xFF, 0xFF, 0x1F, - 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x77, - 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, 0x17, 0x08, 0x08, 0xA6, 0xA6, - 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x04, 0x04, - 0x04, 0x04, 0x17, 0x04, 0x04, 0x17, 0x04, 0x3C, 0x1F, 0x1F, 0x1F, 0x1F, - 0x17, 0x04, 0x04, 0x17, 0x06, 0x06, 0x00, 0x00, 0x04, 0x08, 0x17, 0x06, - 0x46, 0xA1, 0x01, 0x00, 0x00, 0x32, 0x17, 0x0B, 0x64, 0x01, 0x17, 0x04, - 0x7C, 0x17, 0x07, 0x0C, 0x03, 0x17, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1E, - 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, - 0x17, 0x0B, 0x2C, 0x09, 0x00, 0x00, 0x00, 0x17, 0x05, 0x5D, 0x17, 0x07, - 0x10, 0x0B, 0x17, 0x07, 0x28, 0x08, 0x17, 0x07, 0x0C, 0x17, 0x04, 0x1C, - 0x20, 0x00, 0x00, 0x00, 0x06, 0x17, 0x04, 0x04, 0x17, 0x07, 0x08, 0x17, - 0x04, 0x50, 0x17, 0x04, 0x2C, 0x17, 0x04, 0x1C, 0x17, 0x04, 0x10, 0x17, - 0x08, 0x6C, 0x17, 0x04, 0x10, 0x17, 0x04, 0x38, 0x17, 0x04, 0x40, 0x05, - 0x17, 0x07, 0x1C, 0x17, 0x08, 0x58, 0x17, 0x04, 0x24, 0x17, 0x04, 0x18, - 0x17, 0x08, 0x64, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x17, 0x09, 0x0C, 0x17, 0x05, 0x82, - 0x58, 0x17, 0x07, 0x61, 0xC1, 0x17, 0x07, 0x50, 0x17, 0x04, 0x04, 0x17, - 0x08, 0x81, 0x48, 0x17, 0x04, 0x04, 0x17, 0x04, 0x28, 0x17, 0x04, 0x60, - 0x17, 0x08, 0x54, 0x27, 0x17, 0x04, 0x04, 0x17, 0x07, 0x14, 0x17, 0x04, - 0x04, 0x04, 0x17, 0x07, 0x81, 0x58, 0x17, 0x0C, 0x0C, 0x1C, 0x03, 0x00, - 0x00, 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x17, 0x04, 0x5A, 0xF3, 0x0C, - 0x04, 0x05, 0x1B, 0x06, 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, - 0x08, 0x1D, 0x09, 0x0A, 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, - 0x02, 0x1B, 0x1C, 0x23, 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, - 0x0A, 0x0B, 0x1D, 0x0D, 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, - 0x24, 0x06, 0x07, 0x9A, 0x12, 0x17, 0x05, 0x83, 0x41, 0x00, 0xFF, 0x17, - 0x10, 0x83, 0x6C, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, - 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, - 0x00, 0x0B, 0x08, 0x72, 0x72, 0x0E, 0x0C, 0x17, 0x04, 0x20, 0x08, 0x08, - 0x0D, 0x0C, 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x17, 0x06, - 0x2C, 0x11, 0x08, 0x17, 0x10, 0x84, 0x67, 0x15, 0x00, 0xCC, 0x00, 0x0A, - 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, 0xFF, - 0x0F, 0xFF, 0x0F, 0x17, 0x08, 0x83, 0x4C, 0x01, 0x03, 0x00, 0x70, 0x00, - 0x0C, 0x00, 0x01, 0x17, 0x04, 0x0C, 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, - 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, 0x17, 0x04, 0x10, 0xA0, 0x00, 0x2C, - 0x00, 0x01, 0x37, 0x00, 0x00, 0x00, 0x80, 0x17, 0x06, 0x48, 0x08, 0x00, - 0x04, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, - 0x28, 0x28, 0x17, 0x04, 0x04, 0x11, 0x11, 0x11, 0x11, 0x17, 0x04, 0x04, - 0xBE, 0x00, 0x00, 0x17, 0x05, 0x58, 0x17, 0x08, 0x5C, 0x17, 0x22, 0x85, - 0x6A, 0x17, 0x1A, 0x1A, 0x14, 0x00, 0x12, 0x00, 0x10, 0x17, 0x05, 0x83, - 0x0A, 0x17, 0x16, 0x18, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x17, 0x05, 0x83, 0x0C, 0x17, - 0x04, 0x20, 0x17, 0x18, 0x18, 0x28, 0x00, 0x28, 0x17, 0x04, 0x04, 0x17, - 0x08, 0x08, 0x17, 0x10, 0x10, 0x00, 0x14, 0x17, 0x05, 0x5A, 0x17, 0x04, - 0x5C, 0x17, 0x04, 0x5E, 0x17, 0x04, 0x0E, 0x17, 0x0E, 0x78, 0x17, 0x09, - 0x82, 0x50, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, - 0x17, 0x08, 0x18, 0x80, 0x01, 0x00, 0x00, 0x40, 0x17, 0x04, 0x20, 0x03, - 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, 0x11, 0x17, 0x08, 0x82, 0x58, - 0x17, 0x0C, 0x38, 0x17, 0x1B, 0x81, 0x6C, 0x17, 0x08, 0x85, 0x60, 0x17, - 0x08, 0x86, 0x50, 0x17, 0x08, 0x86, 0x60, 0x17, 0x06, 0x83, 0x21, 0x22, - 0x04, 0xFF, 0xFF, 0xAF, 0x4F, 0x17, 0x0C, 0x86, 0x74, 0x17, 0x08, 0x2C, - 0x8B, 0xFF, 0x07, 0x17, 0x06, 0x81, 0x04, 0x32, 0x54, 0x76, 0x10, 0x47, - 0x32, 0x65, 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, - 0x64, 0x32, 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, - 0x32, 0x67, 0x17, 0x04, 0x24, 0x49, 0x92, 0x24, 0x17, 0x04, 0x04, 0x17, - 0x11, 0x7C, 0x1B, 0x17, 0x04, 0x04, 0x17, 0x13, 0x81, 0x14, 0x2F, 0x41, - 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x17, 0x04, 0x7C, 0xFF, 0xFF, 0xFF, - 0x7F, 0x0B, 0xD7, 0x06, 0x40, 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, - 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x17, 0x06, 0x86, 0x59, - 0x17, 0x0F, 0x89, 0x14, 0x37, 0x17, 0x07, 0x82, 0x72, 0x10, 0x17, 0x06, - 0x83, 0x0D, 0x00, 0x11, 0x01, 0x17, 0x05, 0x85, 0x39, 0x17, 0x04, 0x0E, - 0x0A, 0x17, 0x07, 0x89, 0x29, 0x17, 0x04, 0x1B, 0x17, 0x08, 0x86, 0x77, - 0x17, 0x09, 0x12, 0x20, 0x00, 0x00, 0x00, 0x81, 0x10, 0x09, 0x28, 0x93, - 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, 0x17, 0x18, 0x82, 0x2C, 0xFF, - 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0x17, 0x04, 0x04, 0xDC, 0xDC, - 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x17, 0x04, 0x04, 0x17, 0x04, 0x04, - 0x17, 0x05, 0x82, 0x24, 0x03, 0x07, 0x17, 0x04, 0x04, 0x00, 0x00, 0x24, - 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, - 0x9C, 0x4B, 0x17, 0x04, 0x64, 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, - 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x17, 0x06, 0x85, 0x60, 0x17, - 0x10, 0x82, 0x74, 0x17, 0x08, 0x08, 0x17, 0x08, 0x88, 0x00, 0x17, 0x04, - 0x10, 0x04, 0x17, 0x0B, 0x87, 0x6C, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, - 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x17, 0x08, 0x8B, 0x18, - 0x1F, 0x17, 0x09, 0x81, 0x73, 0x00, 0xFF, 0x00, 0xFF, 0x17, 0x05, 0x86, - 0x48, 0x17, 0x04, 0x0C, 0x17, 0x07, 0x86, 0x34, 0x00, 0x00, 0xF0, 0x17, - 0x09, 0x87, 0x54, 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x17, 0x0C, 0x81, - 0x52, 0x17, 0x0A, 0x1C, 0x17, 0x10, 0x81, 0x6C, 0x17, 0x0A, 0x82, 0x21, - 0x17, 0x07, 0x82, 0x4D, 0x17, 0x0A, 0x8A, 0x1B, 0x17, 0x11, 0x2C, 0x76, - 0x0C, 0x17, 0x0A, 0x8A, 0x67, 0x17, 0x0F, 0x84, 0x28, 0x17, 0x06, 0x34, - 0x17, 0x17, 0x3A, 0x7E, 0x16, 0x40, 0x17, 0x0C, 0x8B, 0x1F, 0x17, 0x2A, - 0x38, 0x1E, 0x17, 0x0A, 0x38, 0x17, 0x13, 0x81, 0x28, 0x00, 0xC0, 0x17, - 0x17, 0x55, 0x46, 0x24, 0x17, 0x0A, 0x81, 0x28, 0x17, 0x14, 0x38, 0x17, - 0x18, 0x81, 0x60, 0x46, 0x2C, 0x17, 0x06, 0x38, 0xEC, 0x17, 0x0D, 0x16, - 0x17, 0x0E, 0x82, 0x3C, 0x17, 0x82, 0x0C, 0x8E, 0x68, 0x17, 0x04, 0x24, - 0x17, 0x5C, 0x8E, 0x68, 0x17, 0x07, 0x82, 0x5F, 0x80, 0x17, 0x87, 0x01, - 0x8E, 0x68, 0x02, 0x17, 0x81, 0x4A, 0x8E, 0x68, 0x17, 0x0C, 0x87, 0x78, - 0x17, 0x85, 0x28, 0x8E, 0x68, 0x17, 0x8E, 0x68, 0x9D, 0x50, 0x17, 0x81, - 0x24, 0x8E, 0x68, 0x17, 0x04, 0x2C, 0x17, 0x28, 0x8E, 0x68, 0x17, 0x04, - 0x30, 0x17, 0x85, 0x3C, 0x8E, 0x68, 0x12, 0x17, 0x07, 0x85, 0x70, 0x17, - 0x88, 0x74, 0x8E, 0x68, 0x17, 0x87, 0x3E, 0x9D, 0x50, 0x0C, 0x17, 0x04, - 0x04, 0x17, 0x12, 0x8E, 0x68, 0x18, 0x17, 0x87, 0x12, 0xBB, 0x20, 0x17, - 0x83, 0x04, 0x9D, 0x50, 0x15, 0x17, 0x05, 0x8D, 0x76, 0x17, 0x0F, 0x8B, - 0x49, 0x17, 0x0B, 0x18, 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, - 0x34, 0x00, 0x36, 0x00, 0x2F, 0x00, 0x33, 0x17, 0x09, 0x84, 0x0C, 0x17, - 0x18, 0x18, 0x17, 0x20, 0x8E, 0x68, 0x15, 0x17, 0x07, 0x5A, 0x17, 0x06, - 0x5E, 0x16, 0x00, 0x15, 0x17, 0x82, 0x40, 0x9D, 0x50, 0x17, 0x86, 0x5F, - 0xBB, 0x20, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x17, 0x81, 0x4F, 0xAC, 0x38, - 0x3B, 0x17, 0x04, 0x04, 0x17, 0x86, 0x30, 0x8E, 0x68, 0x17, 0x81, 0x53, - 0xAC, 0x38, 0x07, 0x17, 0x0D, 0x8E, 0x68, 0xA3, 0x72, 0x17, 0x83, 0x10, - 0x8E, 0x68 -}; diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl index e5c197e..745399d 100644 --- a/bdk/mem/sdram_config_t210b01.inl +++ b/bdk/mem/sdram_config_t210b01.inl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 CTCaer + * Copyright (c) 2020-2021 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, @@ -16,8 +16,6 @@ #define DRAM_CFG_T210B01_SIZE 2104 -#define DRAM_ID2(x) BIT((x) - 7) - static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { /* Specifies the type of memory device */ .memory_type = MEMORY_TYPE_LPDDR4, @@ -109,7 +107,7 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { .emc_pmacro_ca_tx_drive = 0x3F3F3F3F, .emc_pmacro_cmd_tx_drive = 0x00001220, .emc_pmacro_auto_cal_common = 0x00000804, - .emc_pmacro_zcrtl = 0x505050, + .emc_pmacro_zcrtl = 0x00505050, /* Specifies the time for the calibration to stabilize (in microseconds) */ .emc_auto_cal_wait = 0x000001A1, @@ -708,295 +706,314 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { // Samsung LPDDR4X 4GB X1X2 for prototype Iowa. - { 0x000E0022, 0x3AC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x001B0010, 0x3B0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. - { 0x000E0022, 0x3C4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x001B0010, 0x3C8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. - { 0x00490043, 0x3CC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x00420045, 0x3D0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00490047, 0x3D4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x00460047, 0x3D8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. - { 0x00000016, 0x3DC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x00100000, 0x3E0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. - { 0x00490043, 0x3E4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x00420045, 0x3E8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00490047, 0x3EC / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x00460047, 0x3F0 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. - { 0x00000016, 0x3F4 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x00100000, 0x3F8 / 4, DRAM_ID2(7) }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. - { 0x00220022, 0x41C / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_0. - { 0x000E000E, 0x420 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_1. - { 0x00100010, 0x424 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_2. - { 0x001B001B, 0x428 / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_3. - { 0x00000022, 0x42C / 4, DRAM_ID2(7) }, // emc_pmacro_ddll_long_cmd_4. + { 0x000E0022, 0x3AC / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x001B0010, 0x3B0 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x000E0022, 0x3C4 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x001B0010, 0x3C8 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x00490043, 0x3CC / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00420045, 0x3D0 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00490047, 0x3D4 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x00460047, 0x3D8 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x00000016, 0x3DC / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00100000, 0x3E0 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. + { 0x00490043, 0x3E4 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00420045, 0x3E8 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00490047, 0x3EC / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x00460047, 0x3F0 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x00000016, 0x3F4 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00100000, 0x3F8 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. + { 0x00220022, 0x41C / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ddll_long_cmd_0. + { 0x000E000E, 0x420 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ddll_long_cmd_1. + { 0x00100010, 0x424 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ddll_long_cmd_2. + { 0x001B001B, 0x428 / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000022, 0x42C / 4, LPDDR4X_4GB_SAMSUNG_X1X2 }, // emc_pmacro_ddll_long_cmd_4. - // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ for SDEV Iowa and Hoag. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_adr_cfg. 2 Ranks. - { 0x00000006, 0x1CC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse. - { 0x00000005, 0x1D0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_quse_width. - { 0x00000003, 0x1DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_einput. - { 0x0000000C, 0x1E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_einput_duration. - { 0x08010004, 0x2B8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw1. - { 0x08020000, 0x2BC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw2. - { 0x080D0000, 0x2C0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw3. - { 0x08033131, 0x2C8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw6. - { 0x080B0000, 0x2CC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw8. - { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw9. - { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw10. - { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw12. - { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw13. - { 0x08161414, 0x2E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw14. - { 0x08010004, 0x2E4 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_mrw_extra. - { 0x00000000, 0x340 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_dev_select. Both devices. - { 0x35353535, 0x350 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_vref_dq_0. - { 0x35353535, 0x354 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_vref_dq_1. - { 0x00100010, 0x3FC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. - { 0x00100010, 0x400 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. - { 0x00100010, 0x404 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. - { 0x00100010, 0x408 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. - { 0x00100010, 0x40C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. - { 0x00100010, 0x410 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. - { 0x00100010, 0x414 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. - { 0x00100010, 0x418 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. - { 0x0051004F, 0x450 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_zcal_mrw_cmd. - { 0x40000001, 0x45C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_zcal_init_dev1. - { 0x00000000, 0x594 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd4. - { 0x00001000, 0x598 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_adr_cfg. 2 Ranks. - { 0x00002000, 0x64C / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_cfg. 8GB total density. - { 0x00000002, 0x680 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_timing_r2r. - { 0x02020001, 0x694 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_emem_arb_da_turns. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(9) | DRAM_ID2(13) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ Die-M for SDEV Iowa and Hoag. + { 0x05500000, 0x0D4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_adr_cfg. 2 Ranks. + { 0x00000006, 0x1CC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_einput_duration. + { 0x08010004, 0x2B8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_dev_select. Both devices. + { 0x35353535, 0x350 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_vref_dq_0. + { 0x35353535, 0x354 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_vref_dq_1. + { 0x00100010, 0x3FC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. + { 0x00100010, 0x400 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. + { 0x00100010, 0x404 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. + { 0x00100010, 0x408 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. + { 0x00100010, 0x40C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. + { 0x00100010, 0x410 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. + { 0x00100010, 0x414 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. + { 0x00100010, 0x418 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. + { 0x0051004F, 0x450 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_emem_adr_cfg. 2 Ranks. + { 0x00002000, 0x64C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_emem_cfg. 8GB total density. + { 0x00000002, 0x680 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_video_protect_gpu_override1. - // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT for Iowa and Hoag. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_auto_cal_vref_sel0. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // emc_dyn_self_ref_control. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(11) | DRAM_ID2(15) }, // mc_video_protect_gpu_override1. + // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT Die-E for retail Iowa and Hoag. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_auto_cal_vref_sel0. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_dyn_self_ref_control. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB Die-Y for Iowa. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(16) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(16) }, // emc_auto_cal_vref_sel0. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(16) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(16) }, // emc_dyn_self_ref_control. - { 0x32323232, 0x350 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_vref_dq_0. - { 0x32323232, 0x354 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_vref_dq_1. - { 0x000F0018, 0x3AC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x000F0018, 0x3C4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x00440048, 0x3CC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x00440045, 0x3D0 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00470047, 0x3D4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x0005000D, 0x3DC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x00440048, 0x3E4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x00440045, 0x3E8 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00470047, 0x3EC / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x0005000D, 0x3F4 / 4, DRAM_ID2(16) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x00780078, 0x3FC / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. - { 0x00780078, 0x400 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. - { 0x00780078, 0x404 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. - { 0x00780078, 0x408 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. - { 0x00780078, 0x40C / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. - { 0x00780078, 0x410 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. - { 0x00780078, 0x414 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. - { 0x00780078, 0x418 / 4, DRAM_ID2(16) }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. - { 0x00180018, 0x41C / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_0. - { 0x000F000F, 0x420 / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_1. - { 0x00000018, 0x42C / 4, DRAM_ID2(16) }, // emc_pmacro_ddll_long_cmd_4. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(16) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 4GB (Y01) Die-? for Iowa. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_auto_cal_vref_sel0. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_dyn_self_ref_control. + { 0x32323232, 0x350 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_vref_dq_0. + { 0x32323232, 0x354 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_vref_dq_1. + { 0x000F0018, 0x3AC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00780078, 0x3FC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. + { 0x00780078, 0x400 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. + { 0x00780078, 0x404 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. + { 0x00780078, 0x408 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. + { 0x00780078, 0x40C / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. + { 0x00780078, 0x410 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. + { 0x00780078, 0x414 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. + { 0x00780078, 0x418 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. + { 0x00180018, 0x41C / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_pmacro_ddll_long_cmd_4. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_SAMSUNG_Y }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB 10nm-class (1y) Die-X for Iowa, Hoag and Aula. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_auto_cal_vref_sel0. - { 0x00000006, 0x1CC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_quse. - { 0x00000005, 0x1D0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_quse_width. - { 0x00000003, 0x1DC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_einput. - { 0x0000000C, 0x1E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_einput_duration. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // emc_dyn_self_ref_control. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(17) | DRAM_ID2(19) | DRAM_ID2(24) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 4GB K4U6E3S4AA-MGCL 10nm-class (1y-X03) Die-A for retail Iowa, Hoag and Aula. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_einput_duration. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // emc_dyn_self_ref_control. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 8GB 10nm-class (1y) Die-X for SDEV Iowa and Aula. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_adr_cfg. 2 Ranks. - { 0x00000006, 0x1CC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse. - { 0x00000005, 0x1D0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_quse_width. - { 0x00000003, 0x1DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_einput. - { 0x0000000C, 0x1E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_einput_duration. - { 0x00000008, 0x24C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_tfaw. - { 0x08010004, 0x2B8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw1. - { 0x08020000, 0x2BC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw2. - { 0x080D0000, 0x2C0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw3. - { 0x08033131, 0x2C8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw6. - { 0x080B0000, 0x2CC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw8. - { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw9. - { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw10. - { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw12. - { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw13. - { 0x08161414, 0x2E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw14. - { 0x08010004, 0x2E4 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_mrw_extra. - { 0x00000000, 0x340 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_dev_select. Both devices. - { 0x0051004F, 0x450 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_zcal_mrw_cmd. - { 0x40000001, 0x45C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_zcal_init_dev1. - { 0x00000000, 0x594 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd4. - { 0x00001000, 0x598 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_adr_cfg. 2 Ranks. - { 0x00002000, 0x64C / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_cfg. 8GB total density. - { 0x00000001, 0x670 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_faw. - { 0x00000002, 0x680 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_timing_r2r. - { 0x02020001, 0x694 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_emem_arb_da_turns. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(18) | DRAM_ID2(23) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 8GB K4UBE3D4AA-MGCL 10nm-class (1y-X03) Die-A for SDEV Iowa, Hoag and Aula. + { 0x05500000, 0x0D4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_adr_cfg. 2 Ranks. + { 0x00000006, 0x1CC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_tfaw. + { 0x08010004, 0x2B8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_dev_select. Both devices. + { 0x0051004F, 0x450 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_emem_adr_cfg. 2 Ranks. + { 0x00002000, 0x64C / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_emem_cfg. 8GB total density. + { 0x00000001, 0x670 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_emem_arb_timing_faw. + { 0x00000002, 0x680 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB 10nm-class (1y) Die-Y for Iowa. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(20) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(20) }, // emc_auto_cal_vref_sel0. - { 0x00000008, 0x24C / 4, DRAM_ID2(20) }, // emc_tfaw. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(20) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(20) }, // emc_dyn_self_ref_control. - { 0x000F0018, 0x3AC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x000F0018, 0x3C4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x00440048, 0x3CC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x00440045, 0x3D0 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00470047, 0x3D4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x0005000D, 0x3DC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x00440048, 0x3E4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x00440045, 0x3E8 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00470047, 0x3EC / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x0005000D, 0x3F4 / 4, DRAM_ID2(20) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x00180018, 0x41C / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_0. - { 0x000F000F, 0x420 / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_1. - { 0x00000018, 0x42C / 4, DRAM_ID2(20) }, // emc_pmacro_ddll_long_cmd_4. - { 0x00000001, 0x670 / 4, DRAM_ID2(20) }, // mc_emem_arb_timing_faw. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(20) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(20) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 4GB 10nm-class (1y-Y01) Die-? for Iowa. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_auto_cal_vref_sel0. + { 0x00000008, 0x24C / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_dyn_self_ref_control. + { 0x000F0018, 0x3AC / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00180018, 0x41C / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_4. + { 0x00000001, 0x670 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // mc_emem_arb_timing_faw. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_Y }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 8GB 10nm-class (1y) Die-Y for SDEV Iowa. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(21) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(21) }, // emc_auto_cal_vref_sel0. - { 0x00000001, 0x134 / 4, DRAM_ID2(21) }, // emc_adr_cfg. 2 Ranks. - { 0x00000008, 0x24C / 4, DRAM_ID2(21) }, // emc_tfaw. - { 0x08010004, 0x2B8 / 4, DRAM_ID2(21) }, // emc_mrw1. - { 0x08020000, 0x2BC / 4, DRAM_ID2(21) }, // emc_mrw2. - { 0x080D0000, 0x2C0 / 4, DRAM_ID2(21) }, // emc_mrw3. - { 0x08033131, 0x2C8 / 4, DRAM_ID2(21) }, // emc_mrw6. - { 0x080B0000, 0x2CC / 4, DRAM_ID2(21) }, // emc_mrw8. - { 0x0C0E5D5D, 0x2D0 / 4, DRAM_ID2(21) }, // emc_mrw9. - { 0x080C5D5D, 0x2D4 / 4, DRAM_ID2(21) }, // emc_mrw10. - { 0x0C0D0808, 0x2D8 / 4, DRAM_ID2(21) }, // emc_mrw12. - { 0x0C0D0000, 0x2DC / 4, DRAM_ID2(21) }, // emc_mrw13. - { 0x08161414, 0x2E0 / 4, DRAM_ID2(21) }, // emc_mrw14. - { 0x08010004, 0x2E4 / 4, DRAM_ID2(21) }, // emc_mrw_extra. - { 0x00000000, 0x340 / 4, DRAM_ID2(21) }, // emc_dev_select. Both devices. - { 0x32323232, 0x350 / 4, DRAM_ID2(21) }, // emc_pmacro_ib_vref_dq_0. - { 0x32323232, 0x354 / 4, DRAM_ID2(21) }, // emc_pmacro_ib_vref_dq_1. - { 0x000F0018, 0x3AC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x000F0018, 0x3C4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x00440048, 0x3CC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x00440045, 0x3D0 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00470047, 0x3D4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x0005000D, 0x3DC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x00440048, 0x3E4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x00440045, 0x3E8 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00470047, 0x3EC / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x0005000D, 0x3F4 / 4, DRAM_ID2(21) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x00180018, 0x41C / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_0. - { 0x000F000F, 0x420 / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_1. - { 0x00000018, 0x42C / 4, DRAM_ID2(21) }, // emc_pmacro_ddll_long_cmd_4. - { 0x0051004F, 0x450 / 4, DRAM_ID2(21) }, // emc_zcal_mrw_cmd. - { 0x40000001, 0x45C / 4, DRAM_ID2(21) }, // emc_zcal_init_dev1. - { 0x00000000, 0x594 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd4. - { 0x00001000, 0x598 / 4, DRAM_ID2(21) }, // emc_pmacro_tx_pwrd5. - { 0x00000001, 0x630 / 4, DRAM_ID2(21) }, // mc_emem_adr_cfg. 2 Ranks. - { 0x00002000, 0x64C / 4, DRAM_ID2(21) }, // mc_emem_cfg. 8GB total density. - { 0x00000001, 0x670 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_faw. - { 0x00000002, 0x680 / 4, DRAM_ID2(21) }, // mc_emem_arb_timing_r2r. - { 0x02020001, 0x694 / 4, DRAM_ID2(21) }, // mc_emem_arb_da_turns. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(21) }, // mc_video_protect_gpu_override1. + // Samsung LPDDR4X 8GB 10nm-class (1y-Y01) Die-? for SDEV Iowa. + { 0x05500000, 0x0D4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_auto_cal_vref_sel0. + { 0x00000001, 0x134 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_adr_cfg. 2 Ranks. + { 0x00000008, 0x24C / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_tfaw. + { 0x08010004, 0x2B8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_dev_select. Both devices. + { 0x32323232, 0x350 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ib_vref_dq_0. + { 0x32323232, 0x354 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ib_vref_dq_1. + { 0x000F0018, 0x3AC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x000F0018, 0x3C4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00440048, 0x3CC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00440045, 0x3D0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00470047, 0x3D4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0005000D, 0x3DC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x00440048, 0x3E4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00440045, 0x3E8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00470047, 0x3EC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0005000D, 0x3F4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00180018, 0x41C / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_0. + { 0x000F000F, 0x420 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_1. + { 0x00000018, 0x42C / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_ddll_long_cmd_4. + { 0x0051004F, 0x450 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_zcal_init_dev1. + { 0x00000000, 0x594 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_tx_pwrd4. + { 0x00001000, 0x598 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_emem_adr_cfg. 2 Ranks. + { 0x00002000, 0x64C / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_emem_cfg. 8GB total density. + { 0x00000001, 0x670 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_emem_arb_timing_faw. + { 0x00000002, 0x680 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_emem_arb_da_turns. + { 0x2A800000, 0x6DC / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_video_protect_gpu_override1. - // Samsung LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Aula. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(22) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(22) }, // emc_auto_cal_vref_sel0. - { 0x00000008, 0x24C / 4, DRAM_ID2(22) }, // emc_tfaw. - { 0x1C041B06, 0x26C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_0. - { 0x02050307, 0x270 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_1. - { 0x03252500, 0x274 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd0_2. - { 0x081D1E00, 0x278 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_0. - { 0x090C0A0D, 0x27C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_1. - { 0x0526260B, 0x280 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd1_2. - { 0x05030402, 0x284 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_0. - { 0x1B1C0600, 0x288 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_1. - { 0x07252507, 0x28C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd2_2. - { 0x0C1D0B0A, 0x290 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_0. - { 0x0800090D, 0x294 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_1. - { 0x0926261E, 0x298 / 4, DRAM_ID2(22) }, // emc_cmd_mapping_cmd3_2. - { 0x2A080624, 0x29C / 4, DRAM_ID2(22) }, // emc_cmd_mapping_byte. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(22) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(22) }, // emc_dyn_self_ref_control. - { 0x00140010, 0x3AC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x0013000B, 0x3B0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. - { 0x00140010, 0x3C4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x0013000B, 0x3C8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. - { 0x00450047, 0x3CC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x004D004F, 0x3D0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00460046, 0x3D4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x00480048, 0x3D8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. - { 0x000C0008, 0x3DC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x000B000C, 0x3E0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. - { 0x00450047, 0x3E4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x004D004F, 0x3E8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00460046, 0x3EC / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x00480048, 0x3F0 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. - { 0x000C0008, 0x3F4 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x000B000C, 0x3F8 / 4, DRAM_ID2(22) }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. - { 0x00100010, 0x41C / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_0. - { 0x00140014, 0x420 / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_1. - { 0x00130013, 0x428 / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_3. - { 0x00000010, 0x42C / 4, DRAM_ID2(22) }, // emc_pmacro_ddll_long_cmd_4. - { 0x40280100, 0x4B4 / 4, DRAM_ID2(22) }, // pmc_ddr_cfg. - { 0x4F9F9FFF, 0x4B8 / 4, DRAM_ID2(22) }, // pmc_io_dpd3_req. - { 0x64032157, 0x4D8 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte0. - { 0x51320467, 0x4DC / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte1. - { 0x04735621, 0x4E0 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte2. - { 0x47356012, 0x4E4 / 4, DRAM_ID2(22) }, // emc_swizzle_rank0_byte3. - { 0x12045673, 0x4E8 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte0. - { 0x43657210, 0x4EC / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte1. - { 0x65402137, 0x4F0 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte2. - { 0x57302164, 0x4F4 / 4, DRAM_ID2(22) }, // emc_swizzle_rank1_byte3. - { 0x4F9F9FFF, 0x534 / 4, DRAM_ID2(22) }, // emc_pmc_scratch1. - { 0x4033CF1F, 0x53C / 4, DRAM_ID2(22) }, // emc_pmc_scratch3. - { 0x10000000, 0x590 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd3. - { 0x00030108, 0x594 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd4. - { 0x01400050, 0x598 / 4, DRAM_ID2(22) }, // emc_pmacro_tx_pwrd5. - { 0x29081081, 0x5A0 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping0. - { 0x54A59332, 0x5A4 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping1. - { 0x87766B4A, 0x5A8 / 4, DRAM_ID2(22) }, // emc_pmacro_brick_mapping2. - { 0x00000001, 0x670 / 4, DRAM_ID2(22) }, // mc_emem_arb_timing_faw. - { 0xE4FACB43, 0x6D4 / 4, DRAM_ID2(22) }, // mc_video_protect_vpr_override. + TSEC, NVENC. - { 0x0600FED3, 0x6D8 / 4, DRAM_ID2(22) }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(22) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(22) }, // mc_video_protect_gpu_override1. - { 0x0000009C, 0x814 / 4, DRAM_ID2(22) }, // swizzle_rank_byte_encode. +/* + // Samsung LPDDR4X 4GB 10nm-class (1y-A01) Die-? for prototype (?) Aula. Unused. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_auto_cal_vref_sel0. + { 0x00000008, 0x24C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_tfaw. + { 0x1C041B06, 0x26C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_0. + { 0x02050307, 0x270 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_1. + { 0x03252500, 0x274 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_2. + { 0x081D1E00, 0x278 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_0. + { 0x090C0A0D, 0x27C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_1. + { 0x0526260B, 0x280 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_2. + { 0x05030402, 0x284 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_0. + { 0x1B1C0600, 0x288 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_1. + { 0x07252507, 0x28C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_2. + { 0x0C1D0B0A, 0x290 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_0. + { 0x0800090D, 0x294 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_1. + { 0x0926261E, 0x298 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_2. + { 0x2A080624, 0x29C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_byte. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_dyn_self_ref_control. + { 0x00140010, 0x3AC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x0013000B, 0x3B0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x00140010, 0x3C4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x0013000B, 0x3C8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x00450047, 0x3CC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x004D004F, 0x3D0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00460046, 0x3D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x00480048, 0x3D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x000C0008, 0x3DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x000B000C, 0x3E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. + { 0x00450047, 0x3E4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x004D004F, 0x3E8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00460046, 0x3EC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x00480048, 0x3F0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x000C0008, 0x3F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x000B000C, 0x3F8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. + { 0x00100010, 0x41C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_0. + { 0x00140014, 0x420 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_1. + { 0x00130013, 0x428 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000010, 0x42C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_4. + { 0x40280100, 0x4B4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // pmc_ddr_cfg. + { 0x4F9F9FFF, 0x4B8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // pmc_io_dpd3_req. + { 0x64032157, 0x4D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte0. + { 0x51320467, 0x4DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte1. + { 0x04735621, 0x4E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte2. + { 0x47356012, 0x4E4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte3. + { 0x12045673, 0x4E8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte0. + { 0x43657210, 0x4EC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte1. + { 0x65402137, 0x4F0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte2. + { 0x57302164, 0x4F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte3. + { 0x4F9F9FFF, 0x534 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmc_scratch1. + { 0x4033CF1F, 0x53C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmc_scratch3. + { 0x10000000, 0x590 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd3. + { 0x00030108, 0x594 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd4. + { 0x01400050, 0x598 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd5. + { 0x29081081, 0x5A0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping0. + { 0x54A59332, 0x5A4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping1. + { 0x87766B4A, 0x5A8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping2. + { 0x00000001, 0x670 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_emem_arb_timing_faw. + { 0xE4FACB43, 0x6D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_vpr_override. + TSEC, NVENC. + { 0x0600FED3, 0x6D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_gpu_override1. + { 0x0000009C, 0x814 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // swizzle_rank_byte_encode. +*/ + // Micron LPDDR4X 4GB 10nm-class (1y-01) Die-A for Unknown Iowa/Hoag/Aula. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_dyn_self_ref_control. + { 0x00000001, 0x670 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_emem_arb_timing_faw. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_video_protect_gpu_override1. - // Micron LPDDR4X 4GB 10nm-class (1y) Die-A for Unknown Iowa/Hoag/Aula. - { 0x05500000, 0x0D4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_auto_cal_vref_sel0. - { 0x00000006, 0x1CC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_quse. - { 0x00000005, 0x1D0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_quse_width. - { 0x00000003, 0x1DC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_einput. - { 0x0000000C, 0x1E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_einput_duration. - { 0x00000008, 0x24C / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_tfaw. - { 0x88161414, 0x2E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_mrw14. - { 0x80000713, 0x32C / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // emc_dyn_self_ref_control. - { 0x00000001, 0x670 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_emem_arb_timing_faw. - { 0x2A800000, 0x6DC / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, DRAM_ID2(25) | DRAM_ID2(26) | DRAM_ID2(27) }, // mc_video_protect_gpu_override1. + // Hynix LPDDR4X 4GB 10nm-class (1y-01) Die-A for Unknown Iowa/Hoag/Aula. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_dyn_self_ref_control. + { 0x00000001, 0x670 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // mc_emem_arb_timing_faw. + { 0xE4FACB43, 0x6D4 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // mc_video_protect_vpr_override. + TSEC, NVENC. + { 0x0600FED3, 0x6D8 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // mc_video_protect_gpu_override1. + + //!TODO: Too many duplicates. }; diff --git a/bdk/power/regulator_5v.c b/bdk/power/regulator_5v.c index 64fd7d7..7b8924b 100644 --- a/bdk/power/regulator_5v.c +++ b/bdk/power/regulator_5v.c @@ -21,25 +21,25 @@ #include static u8 reg_5v_dev = 0; -static bool batt_src = false; +static bool usb_src = false; void regulator_5v_enable(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). + // Fan and Rail power from battery 5V regulator. 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); - batt_src = true; - // Fan and Rail power from USB 5V VDD. + // Fan and Rail power from USB 5V VBUS. 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); + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + usb_src = false; // Make sure GPIO power is enabled. PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN; @@ -55,18 +55,18 @@ void regulator_5v_disable(u8 dev) if (!reg_5v_dev) { - // Rail power from internal 5V regulator (battery). + // Rail power from battery 5V regulator. 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; - batt_src = false; - // Rail power from USB 5V VDD. + // Rail power from USB 5V VBUS. 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; + usb_src = false; // GPIO AO IO rails. PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN; @@ -78,16 +78,16 @@ bool regulator_5v_get_dev_enabled(u8 dev) return (reg_5v_dev & dev); } -void regulator_5v_batt_src_enable(bool enable) +void regulator_5v_usb_src_enable(bool enable) { - if (enable && !batt_src) + if (enable && !usb_src) { - gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH); - batt_src = true; + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH); + usb_src = true; } - else if (!enable && batt_src) + else if (!enable && usb_src) { - gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW); - batt_src = false; + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + usb_src = false; } } diff --git a/bdk/power/regulator_5v.h b/bdk/power/regulator_5v.h index b7d7490..527c18a 100644 --- a/bdk/power/regulator_5v.h +++ b/bdk/power/regulator_5v.h @@ -30,6 +30,6 @@ enum void regulator_5v_enable(u8 dev); void regulator_5v_disable(u8 dev); bool regulator_5v_get_dev_enabled(u8 dev); -void regulator_5v_batt_src_enable(bool enable); +void regulator_5v_usb_src_enable(bool enable); #endif \ No newline at end of file diff --git a/bdk/sec/se.c b/bdk/sec/se.c index a879cb0..45652dc 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -255,7 +255,7 @@ int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_siz // Copy output hash. u32 *dst32 = (u32 *)dst; for (u32 i = 0; i < dst_size / 4; i++) - dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT_REG + (i << 2))); + dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT_REG + (i * 4))); return res; } @@ -485,7 +485,7 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst tweak[i] = sec & 0xFF; sec >>= 8; } - if (!se_aes_crypt_block_ecb(tweak_ks, 1, tweak, tweak)) + if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak)) return 0; memcpy(orig_tweak, tweak, 0x10); @@ -538,7 +538,7 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) u8 *last_block = (u8 *)calloc(0x10, 1); // generate derived key - if (!se_aes_crypt_block_ecb(ks, 1, key, key)) + if (!se_aes_crypt_block_ecb(ks, ENCRYPT, key, key)) goto out; _gf256_mul_x(key); if (src_size & 0xF) @@ -668,7 +668,7 @@ int se_calc_sha256_finalize(void *hash, u32 *msg_left) // Copy output hash. for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) - hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i << 2))); + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4))); memcpy(hash, hash32, SE_SHA_256_SIZE); return res; @@ -841,6 +841,6 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) // Decrypt context. se_aes_key_clear(3); se_aes_key_set(3, srk, SE_KEY_128_SIZE); - se_aes_crypt_cbc(3, 0, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize); + se_aes_crypt_cbc(3, DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize); se_aes_key_clear(3); } diff --git a/bdk/sec/se_t210.h b/bdk/sec/se_t210.h index 0233e1d..350bc15 100644 --- a/bdk/sec/se_t210.h +++ b/bdk/sec/se_t210.h @@ -50,6 +50,9 @@ #define SE_RSA1536_DIGEST_SIZE 192 #define SE_RSA2048_DIGEST_SIZE 256 +#define DECRYPT 0 +#define ENCRYPT 1 + /* SE register definitions */ #define SE_SE_SECURITY_REG 0x000 #define SE_HARD_SETTING BIT(0) diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index c154062..ad13b87 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -33,7 +33,8 @@ // #include #define PKG11_MAGIC 0x31314B50 -#define KB_TSEC_FW_EMU_COMPAT 6 // KB ID for HOS 6.2.0. + +#define TSEC_HOS_KB_620 6 static int _tsec_dma_wait_idle() { @@ -62,10 +63,13 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse return _tsec_dma_wait_idle(); } -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) +int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) { int res = 0; u8 *fwbuf = NULL; + u32 type = tsec_ctxt->type; + u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; + u32 *pkg11_magic_off; bpmp_mmu_disable(); bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); @@ -81,7 +85,10 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) kfuse_wait_ready(); - //Configure Falcon. + if (type == TSEC_FW_TYPE_NEW) + mc_enable_ahb_redirect(true); + + // Configure Falcon. TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_IRQMSET) = TSEC_IRQMSET_EXT(0xFF) | @@ -103,8 +110,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) goto out; } - //Load firmware or emulate memio environment for newer TSEC fw. - if (kb == KB_TSEC_FW_EMU_COMPAT) + // Load firmware or emulate memio environment for newer TSEC fw. + if (type == TSEC_FW_TYPE_EMU) TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; else { @@ -123,40 +130,159 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } } - //Execute firmware. + if (type == TSEC_FW_TYPE_EMU) + { + // Init SMMU translation for TSEC. + pdir = smmu_init_for_tsec(); + smmu_init(tsec_ctxt->secmon_base); + // Enable SMMU + if (!smmu_is_used()) + smmu_enable(); + + // Clock reset controller. + car = page_alloc(1); + memcpy(car, (void *)CLOCK_BASE, 0x1000); + car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; + smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); + + // Fuse driver. + fuse = page_alloc(1); + memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); + fuse[0x82C / 4] = 0; + fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; + fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; + smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); + + // Power management controller. + pmc = page_alloc(1); + smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); + + // Flow control. + flowctrl = page_alloc(1); + smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); + + // Security engine. + se = page_alloc(1); + memcpy(se, (void *)SE_BASE, 0x1000); + smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); + + // Memory controller. + mc = page_alloc(1); + memcpy(mc, (void *)MC_BASE, 0x1000); + mc[MC_IRAM_BOM / 4] = 0; + mc[MC_IRAM_TOM / 4] = 0x80000000; + smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); + + // IRAM + iram = page_alloc(0x30); + memcpy(iram, tsec_ctxt->pkg1, 0x30000); + // PKG1.1 magic offset. + pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); + smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); + + // Exception vectors + evec = page_alloc(1); + smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); + } + + // Execute firmware. HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; TSEC(TSEC_STATUS) = 0; TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - if (!_tsec_dma_wait_idle()) + if (type == TSEC_FW_TYPE_EMU) { - res = -3; - goto out_free; - } - u32 timeout = get_tmr_ms() + 4000; - while (!(TSEC(TSEC_CPUCTL) & TSEC_CPUCTL_KEYGEN_DONE)) - if (get_tmr_ms() > timeout) + u32 start = get_tmr_us(); + u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; + u32 key[16] = {0}; + u32 kidx = 0; + + while (*pkg11_magic_off != PKG11_MAGIC) { - res = -4; + smmu_flush_all(); + + if (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]) + { + k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; + key[kidx++] = k; + } + + // Failsafe. + if ((u32)get_tmr_us() - start > 125000) + break; + } + + if (kidx != 8) + { + res = -6; + smmu_deinit_for_tsec(); + goto out_free; } - if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) - { - res = -5; - goto out_free; - } - //Fetch result. - HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; + // Give some extra time to make sure PKG1.1 is decrypted. + msleep(50); + + memcpy(tsec_keys, &key, 0x20); + memcpy(tsec_ctxt->pkg1, iram, 0x30000); + + smmu_deinit_for_tsec(); + + // for (int i = 0; i < kidx; i++) + // gfx_printf("key %08X\n", key[i]); + + // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); + + // u32 errst = MC(MC_ERR_STATUS); + // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); + // gfx_printf(" type: %02X\n", errst >> 28); + // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3); + // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); + // gfx_printf(" cid: %02x\n", errst & 0xFF); + } + else + { + if (!_tsec_dma_wait_idle()) + { + res = -3; + goto out_free; + } + u32 timeout = get_tmr_ms() + 2000; + while (!TSEC(TSEC_STATUS)) + if (get_tmr_ms() > timeout) + { + res = -4; + goto out_free; + } + if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) + { + res = -5; + goto out_free; + } + + // Fetch result. + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; + u32 buf[4]; + buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); + buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); + buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); + buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); + SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; + + memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); + } out_free:; free(fwbuf); out:; - //Disable clocks. + // Disable clocks. clock_disable_kfuse(); clock_disable_sor1(); clock_disable_sor0(); @@ -165,28 +291,8 @@ out:; bpmp_mmu_enable(); bpmp_clk_rate_set(prev_fid); - return res; -} - -int tsec_run_fw(tsec_ctxt_t *tsec_ctxt) -{ - /* Ensure that the ahb redirect is enabled. */ - mc_enable_ahb_redirect(); - - /* Get bom/tom */ - u32 bom = MC(MC_IRAM_BOM); - u32 tom = MC(MC_IRAM_TOM); - - /* Override the ahb redirect extents. */ - MC(MC_IRAM_BOM) = 0x40000000; - MC(MC_IRAM_TOM) = 0x80000000; - - /* Run the fw. */ - int res = tsec_query(NULL, 0, tsec_ctxt); - - /* Reset the ahb redirect extents. */ - MC(MC_IRAM_BOM) = bom; - MC(MC_IRAM_TOM) = tom; + if (type == TSEC_FW_TYPE_NEW) + mc_disable_ahb_redirect(); return res; } diff --git a/bdk/sec/tsec.h b/bdk/sec/tsec.h index 47c9f45..734ca41 100644 --- a/bdk/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer +* Copyright (c) 2018-2021 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, @@ -20,33 +20,24 @@ #include -#define TSEC_KEY_DATA_OFFSET 0x300 +enum tsec_fw_type +{ + // Retail Hovi Keygen. + TSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0. + TSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated enviroment. + TSEC_FW_TYPE_NEW = 2, // 7.0.0+. +}; typedef struct _tsec_ctxt_t { const void *fw; u32 size; + u32 type; void *pkg1; + u32 pkg11_off; + u32 secmon_base; } tsec_ctxt_t; -typedef struct _tsec_key_data_t -{ - u8 debug_key[0x10]; - u8 blob0_auth_hash[0x10]; - u8 blob1_auth_hash[0x10]; - u8 blob2_auth_hash[0x10]; - u8 blob2_aes_iv[0x10]; - u8 hovi_eks_seed[0x10]; - u8 hovi_common_seed[0x10]; - u32 blob0_size; - u32 blob1_size; - u32 blob2_size; - u32 blob3_size; - u32 blob4_size; - u8 reserved[0x7C]; -} tsec_key_data_t; - -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); -int tsec_run_fw(tsec_ctxt_t *tsec_ctxt); +int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt); #endif diff --git a/bdk/sec/tsec_t210.h b/bdk/sec/tsec_t210.h index 9d473cb..889d0d4 100644 --- a/bdk/sec/tsec_t210.h +++ b/bdk/sec/tsec_t210.h @@ -37,7 +37,6 @@ #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_CPUCTL 0x1100 #define TSEC_CPUCTL_STARTCPU BIT(1) -#define TSEC_CPUCTL_KEYGEN_DONE BIT(4) #define TSEC_BOOTVEC 0x1104 #define TSEC_DMACTL 0x110C #define TSEC_DMATRFBASE 0x1110 diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index e350b64..39a50c1 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -2,7 +2,8 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 CTCaer + * Copyright (c) 2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +20,8 @@ #include +#include +#include #include #include #include @@ -99,7 +102,7 @@ u32 fuse_read_dramid(bool raw_id) } else { - if (dramid > 27) + if (dramid > 28) dramid = 8; } @@ -120,26 +123,41 @@ u32 fuse_read_hw_type() { switch ((fuse_read_odm(4) & 0xF0000) >> 16) { - case 1: - return FUSE_NX_HW_TYPE_IOWA; case 2: return FUSE_NX_HW_TYPE_HOAG; + case 4: + return FUSE_NX_HW_TYPE_AULA; + case 1: + default: + return FUSE_NX_HW_TYPE_IOWA; } } return FUSE_NX_HW_TYPE_ICOSA; } -u8 fuse_count_burnt(u32 val) +int fuse_set_sbk() { - u8 burnt_fuses = 0; - for (u32 i = 0; i < 32; i++) + if (FUSE(FUSE_PRIVATE_KEY0) != 0xFFFFFFFF) { - if ((val >> i) & 1) - burnt_fuses++; + // Read SBK from fuses. + u32 sbk[4] = { + FUSE(FUSE_PRIVATE_KEY0), + FUSE(FUSE_PRIVATE_KEY1), + FUSE(FUSE_PRIVATE_KEY2), + FUSE(FUSE_PRIVATE_KEY3) + }; + + // Set SBK to slot 14. + se_aes_key_set(14, sbk, SE_KEY_128_SIZE); + + // Lock SBK from being read. + se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); + + return 1; } - return burnt_fuses; + return 0; } void fuse_wait_idle() diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h index 481923c..99759d9 100644 --- a/bdk/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -2,7 +2,8 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 CTCaer + * Copyright (c) 2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -82,7 +83,8 @@ enum { FUSE_NX_HW_TYPE_ICOSA, FUSE_NX_HW_TYPE_IOWA, - FUSE_NX_HW_TYPE_HOAG + FUSE_NX_HW_TYPE_HOAG, + FUSE_NX_HW_TYPE_AULA }; enum @@ -98,7 +100,7 @@ u32 fuse_read_bootrom_rev(); u32 fuse_read_dramid(bool raw_id); u32 fuse_read_hw_state(); u32 fuse_read_hw_type(); -u8 fuse_count_burnt(u32 val); +int fuse_set_sbk(); void fuse_wait_idle(); int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index afde017..5efe5df 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -250,28 +250,14 @@ static void _mbist_workaround() static void _config_se_brom() { - // Enable fuse clock. + // Enable Fuse visibility. clock_enable_fuse(true); - // Skip SBK/SSK if running on patched Erista. - if (!(FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF)) - { - // Bootrom part we skipped. - u32 sbk[4] = { - FUSE(FUSE_PRIVATE_KEY0), - FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), - FUSE(FUSE_PRIVATE_KEY3) - }; - // Set SBK to slot 14. - se_aes_key_set(14, sbk, SE_KEY_128_SIZE); + // Try to set SBK from fuses. If patched, skip. + fuse_set_sbk(); - // Lock SBK from being read. - se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); - - // Lock SSK (although it's not set and unused anyways). - se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); - } + // Lock SSK (although it's not set and unused anyways). + // se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); // This memset needs to happen here, else TZRAM will behave weirdly later on. memset((void *)TZRAM_BASE, 0, 0x10000); @@ -351,7 +337,7 @@ void hw_init() // Enable Security Engine clock. clock_enable_se(); - // Enable Fuse clock. + // Enable Fuse visibility. clock_enable_fuse(true); // Disable Fuse programming. diff --git a/bdk/storage/mmc.h b/bdk/storage/mmc.h index fc6c2f8..ee81e69 100644 --- a/bdk/storage/mmc.h +++ b/bdk/storage/mmc.h @@ -2,6 +2,7 @@ * Header for MultiMediaCard (MMC) * * Copyright 2002 Hewlett-Packard Company + * Copyright 2018-2021 CTCaer * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is @@ -21,8 +22,8 @@ * 15 May 2002 */ -#ifndef LINUX_MMC_MMC_H -#define LINUX_MMC_MMC_H +#ifndef MMC_H +#define MMC_H /* Standard MMC commands (4.1) type argument response */ /* class 1 */ @@ -97,29 +98,29 @@ #define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */ /* -* MMC_SWITCH argument format: -* -* [31:26] Always 0 -* [25:24] Access Mode -* [23:16] Location of target Byte in EXT_CSD -* [15:08] Value Byte -* [07:03] Always 0 -* [02:00] Command Set -*/ + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ /* -MMC status in R1, for native mode (SPI bits are different) -Type -e : error bit -s : status bit -r : detected and set for the actual command response -x : detected and set during command execution. the host must poll -the card by sending status command in order to read these bits. -Clear condition -a : according to the card state -b : always related to the previous command. Reception of -a valid command will clear it (with a delay of one command) -c : clear by read + * MMC status in R1, for native mode (SPI bits are different) + * Type + * e : error bit + * s : status bit + * r : detected and set for the actual command response + * x : detected and set during command execution. the host must poll + * the card by sending status command in order to read these bits. + * Clear condition + * a : according to the card state + * b : always related to the previous command. Reception of a valid + * command will clear it (with a delay of one command) + * c : clear by read */ #define R1_OUT_OF_RANGE (1 << 31) /* er, c */ @@ -151,6 +152,7 @@ c : clear by read #define R1_AKE_SEQ_ERROR (1 << 3) /* R1_CURRENT_STATE 12:9 */ +#define R1_STATE(x) ((x) << 9) #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 @@ -162,9 +164,9 @@ c : clear by read #define R1_STATE_DIS 8 /* -* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS -* R1 is the low order byte; R2 is the next highest byte, when present. -*/ + * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS + * R1 is the low order byte; R2 is the next highest byte, when present. + */ #define R1_SPI_IDLE (1 << 0) #define R1_SPI_ERASE_RESET (1 << 1) #define R1_SPI_ILLEGAL_COMMAND (1 << 2) @@ -185,16 +187,16 @@ c : clear by read #define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE /* -* OCR bits are mostly in host.h -*/ + * OCR bits are mostly in host.h + */ #define MMC_CARD_VDD_18 (1 << 7) /* Card VDD voltage 1.8 */ #define MMC_CARD_VDD_27_34 (0x7F << 15) /* Card VDD voltage 2.7 ~ 3.4 */ #define MMC_CARD_CCS (1 << 30) /* Card Capacity status bit */ #define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */ /* -* Card Command Classes (CCC) -*/ + * Card Command Classes (CCC) + */ #define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ /* (and for SPI, CMD58,59) */ @@ -222,8 +224,8 @@ c : clear by read /* (CMD?) */ /* -* CSD field definitions -*/ + * CSD field definitions + */ #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ @@ -237,8 +239,8 @@ c : clear by read #define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ /* -* EXT_CSD fields -*/ + * EXT_CSD fields + */ #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ #define EXT_CSD_FLUSH_CACHE 32 /* W */ @@ -316,8 +318,8 @@ c : clear by read #define EXT_CSD_HPI_FEATURES 503 /* RO */ /* -* EXT_CSD field definitions -*/ + * EXT_CSD field definitions + */ #define EXT_CSD_WR_REL_PARAM_EN (1<<2) @@ -393,8 +395,8 @@ c : clear by read #define EXT_CSD_PACKED_EVENT_EN (1<<3) /* -* EXCEPTION_EVENT_STATUS field -*/ + * EXCEPTION_EVENT_STATUS field + */ #define EXT_CSD_URGENT_BKOPS (1<<0) #define EXT_CSD_DYNCAP_NEEDED (1<<1) #define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2) @@ -404,34 +406,34 @@ c : clear by read #define EXT_CSD_PACKED_INDEXED_ERROR (1<<1) /* -* BKOPS status level -*/ + * BKOPS status level + */ #define EXT_CSD_BKOPS_LEVEL_2 0x2 /* -* BKOPS modes -*/ + * BKOPS modes + */ #define EXT_CSD_MANUAL_BKOPS_MASK 0x01 #define EXT_CSD_AUTO_BKOPS_MASK 0x02 /* -* Command Queue -*/ + * Command Queue + */ #define EXT_CSD_CMDQ_MODE_ENABLED (1<<0) #define EXT_CSD_CMDQ_DEPTH_MASK 0x1F #define EXT_CSD_CMDQ_SUPPORTED (1<<0) /* -* MMC_SWITCH access modes -*/ + * MMC_SWITCH access modes + */ #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ /* -* Erase/trim/discard -*/ + * Erase/trim/discard + */ #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 #define MMC_TRIM_ARG 0x00000001 @@ -441,4 +443,9 @@ c : clear by read #define MMC_SECURE_ARGS 0x80000000 #define MMC_TRIM_ARGS 0x00008001 -#endif /* LINUX_MMC_MMC_H */ +/* + * Vendor definitions and structs + */ +#define MMC_SANDISK_HEALTH_REPORT 0x96C9D71C + +#endif /* MMC_H */ diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c index 54b19de..c87db83 100644 --- a/bdk/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -139,6 +139,60 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage) return _sdmmc_storage_get_status(storage, &tmp, 0); } +int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_62_CMD, arg, SDMMC_RSP_TYPE_1, 1); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + return 0; + + u32 resp; + sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1); + + resp = -1; + u32 timeout = get_tmr_ms() + 1500; + while (resp != (R1_READY_FOR_DATA | R1_STATE(R1_STATE_TRAN))) + { + _sdmmc_storage_get_status(storage, &resp, 0); + + if (get_tmr_ms() > timeout) + break; + } + + return _sdmmc_storage_check_card_status(resp); +} + +int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf) +{ + // Request health report. + if (!sdmmc_storage_execute_vendor_cmd(storage, MMC_SANDISK_HEALTH_REPORT)) + return 2; + + u32 tmp = 0; + sdmmc_cmd_t cmdbuf; + sdmmc_req_t reqbuf; + + sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_63_CMD, 0, SDMMC_RSP_TYPE_1, 0); // similar to CMD17 with arg 0x0. + + reqbuf.buf = buf; + reqbuf.num_sectors = 1; + reqbuf.blksize = 512; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + u32 blkcnt_out; + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, &blkcnt_out)) + { + sdmmc_stop_transmission(storage->sdmmc, &tmp); + _sdmmc_storage_get_status(storage, &tmp, 0); + + return 0; + } + + return 1; +} + 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; @@ -1360,8 +1414,6 @@ DPRINTF("[SD] SD does not support wide bus width\n"); if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) return 0; DPRINTF("[SD] enabled UHS\n"); - - sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); } else if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0. { @@ -1387,6 +1439,8 @@ DPRINTF("[SD] enabled HS\n"); DPRINTF("[SD] got sd status\n"); } + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); + storage->initialized = 1; return 1; diff --git a/bdk/storage/sdmmc.h b/bdk/storage/sdmmc.h index 2b59f7d..5dcd10f 100644 --- a/bdk/storage/sdmmc.h +++ b/bdk/storage/sdmmc.h @@ -34,6 +34,81 @@ typedef enum _sdmmc_type EMMC_RPMB = 3 } sdmmc_type; +typedef struct _mmc_sandisk_advanced_report_t +{ + u32 power_inits; + + u32 max_erase_cycles_sys; + u32 max_erase_cycles_slc; + u32 max_erase_cycles_mlc; + + u32 min_erase_cycles_sys; + u32 min_erase_cycles_slc; + u32 min_erase_cycles_mlc; + + u32 max_erase_cycles_euda; + u32 min_erase_cycles_euda; + u32 avg_erase_cycles_euda; + u32 read_reclaim_cnt_euda; + u32 bad_blocks_euda; + + u32 pre_eol_euda; + u32 pre_eol_sys; + u32 pre_eol_mlc; + + u32 uncorrectable_ecc; + + u32 temperature_now; + u32 temperature_min; + u32 temperature_max; + + u32 health_pct_euda; + u32 health_pct_sys; + u32 health_pct_mlc; + + u32 unk0; + u32 unk1; + u32 unk2; + + u32 reserved[78]; +} mmc_sandisk_advanced_report_t; + +typedef struct _mmc_sandisk_report_t +{ + u32 avg_erase_cycles_sys; + u32 avg_erase_cycles_slc; + u32 avg_erase_cycles_mlc; + + u32 read_reclaim_cnt_sys; + u32 read_reclaim_cnt_slc; + u32 read_reclaim_cnt_mlc; + + u32 bad_blocks_factory; + u32 bad_blocks_sys; + u32 bad_blocks_slc; + u32 bad_blocks_mlc; + + u32 fw_updates_cnt; + + u8 fw_update_date[12]; + u8 fw_update_time[8]; + + u32 total_writes_100mb; + u32 vdrops; + u32 vdroops; + + u32 vdrops_failed_data_rec; + u32 vdrops_data_rec_ops; + + u32 total_writes_slc_100mb; + u32 total_writes_mlc_100mb; + + u32 mlc_bigfile_mode_limit_exceeded; + u32 avg_erase_cycles_hybrid; + + mmc_sandisk_advanced_report_t advanced; +} mmc_sandisk_report_t; + typedef struct _mmc_cid { u32 manfid; @@ -131,6 +206,9 @@ void sdmmc_storage_init_wait_sd(); 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_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg); +int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf); + int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf); u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage); diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c index 10bd56a..4be2436 100644 --- a/bdk/usb/usb_gadget_ums.c +++ b/bdk/usb/usb_gadget_ums.c @@ -4,7 +4,7 @@ * Copyright (c) 2003-2008 Alan Stern * Copyright (c) 2009 Samsung Electronics * Author: Michal Nazarewicz - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -109,7 +109,7 @@ #define SS_WRITE_ERROR 0x30C02 #define SS_WRITE_PROTECTED 0x72700 -#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. #define ASC(x) ((u8) ((x) >> 8)) #define ASCQ(x) ((u8) (x)) @@ -217,6 +217,7 @@ typedef struct _usbd_gadget_ums_t { u32 tag; u32 residue; u32 usb_amount_left; + bool cbw_req_queued; u32 phase_error; u32 short_packet_received; @@ -368,12 +369,12 @@ static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; } -static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep) +static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout) { if (ep == bulk_ctxt->bulk_in) { bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_writing_finish( - &bulk_ctxt->bulk_in_length_actual); + &bulk_ctxt->bulk_in_length_actual, sync_timeout); if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) { @@ -386,7 +387,7 @@ static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, else { bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish( - &bulk_ctxt->bulk_out_length_actual); + &bulk_ctxt->bulk_out_length_actual, sync_timeout); if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) { @@ -460,6 +461,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) } if (lba_offset >= ums->lun.num_sectors) { + ums->set_text(ums->label, "#FF8000 Warn:# Read - Out of range! Host notified."); ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return UMS_RES_INVALID_ARG; @@ -497,7 +499,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // Wait for the async USB transfer to finish. if (!first_read) - _ums_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in); + _ums_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); lba_offset += amount; amount_left -= amount; @@ -548,6 +550,7 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) if (ums->lun.ro) { + ums->set_text(ums->label, "#FF8000 Warn:# Write - Read only! Host notified."); ums->lun.sense_data = SS_WRITE_PROTECTED; return UMS_RES_INVALID_ARG; @@ -571,19 +574,20 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) // Check that starting LBA is not past the end sector offset. if (lba_offset >= ums->lun.num_sectors) { + ums->set_text(ums->label, "#FF8000 Warn:# Write - Out of range! Host notified."); ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return UMS_RES_INVALID_ARG; } - /* Carry out the file writes */ + // Carry out the file writes. usb_lba_offset = lba_offset; amount_left_to_req = ums->data_size_from_cmnd; amount_left_to_write = ums->data_size_from_cmnd; while (amount_left_to_write > 0) { - /* Queue a request for more data from the host */ + // Queue a request for more data from the host. if (amount_left_to_req > 0) { @@ -638,12 +642,12 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) */ amount = MIN(amount, bulk_ctxt->bulk_out_length); - /* Don't write a partial block */ + // Don't write a partial block. amount -= (amount & 511); if (amount == 0) goto empty_write; - /* Perform the write */ + // Perform the write. if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset, amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf)) amount = 0; @@ -654,7 +658,7 @@ DPRINTF("file write %X @ %X\n", amount, lba_offset); amount_left_to_write -= amount; ums->residue -= amount; - /* If an error occurred, report it and its position */ + // If an error occurred, report it and its position. if (!amount) { ums->set_text(ums->label, "#FFDD00 Error:# SDMMC Write!"); @@ -684,6 +688,7 @@ static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) u32 lba_offset = get_array_be_to_le32(&ums->cmnd[2]); if (lba_offset >= ums->lun.num_sectors) { + ums->set_text(ums->label, "#FF8000 Warn:# Verif - Out of range! Host notified."); ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return UMS_RES_INVALID_ARG; @@ -1005,7 +1010,7 @@ static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) return UMS_RES_INVALID_ARG; } - /* Store the mode data length */ + // Store the mode data length. if (ums->cmnd[0] == SC_MODE_SENSE_6) buf0[0] = len - 1; else @@ -1538,12 +1543,12 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { - /* Was this a real packet? Should it be ignored? */ + // Was this a real packet? Should it be ignored? if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore || ums->lun.unmounted) { if (bulk_ctxt->bulk_out_status || ums->lun.unmounted) { - DPRINTF("USB: EP timeout\n"); + DPRINTF("USB: EP timeout (%d)\n", bulk_ctxt->bulk_out_status); // In case we disconnected, exit UMS. // Raise timeout if removable and didn't got a unit ready command inside 4s. if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_EP_DISABLED || @@ -1574,6 +1579,8 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { ums->set_text(ums->label, "#C7EA46 Status:# Medium unmounted"); ums->timeouts++; + if (!bulk_ctxt->bulk_out_status) + ums->timeouts += 3; } if (ums->timeouts > 20) @@ -1584,27 +1591,32 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) return UMS_RES_INVALID_ARG; } - /* Is the CBW valid? */ + // Clear request flag to allow a new one to be queued. + ums->cbw_req_queued = false; + + // Is the CBW valid? bulk_recv_pkt_t *cbw = (bulk_recv_pkt_t *)bulk_ctxt->bulk_out_buf; if (bulk_ctxt->bulk_out_length_actual != USB_BULK_CB_WRAP_LEN || cbw->Signature != USB_BULK_CB_SIG) { gfx_printf("USB: invalid CBW: len %X sig 0x%X\n", bulk_ctxt->bulk_out_length_actual, cbw->Signature); - // The Bulk-only spec says we MUST stall the IN endpoint - // (6.6.1), so it's unavoidable. It also says we must - // retain this state until the next reset, but there's - // no way to tell the controller driver it should ignore - // Clear-Feature(HALT) requests. - // - // We aren't required to halt the OUT endpoint; instead - // we can simply accept and discard any data received - // until the next reset. + /* + * The Bulk-only spec says we MUST stall the IN endpoint + * (6.6.1), so it's unavoidable. It also says we must + * retain this state until the next reset, but there's + * no way to tell the controller driver it should ignore + * Clear-Feature(HALT) requests. + * + * We aren't required to halt the OUT endpoint; instead + * we can simply accept and discard any data received + * until the next reset. + */ ums_wedge_bulk_in_endpoint(ums); bulk_ctxt->bulk_out_ignore = 1; return UMS_RES_INVALID_ARG; } - /* Is the CBW meaningful? */ + // Is the CBW meaningful? if (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG || cbw->Length == 0 || cbw->Length > SCSI_MAX_CMD_SZ) { @@ -1623,7 +1635,7 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) return UMS_RES_INVALID_ARG; } - /* Save the command for later */ + // Save the command for later. ums->cmnd_size = cbw->Length; memcpy(ums->cmnd, cbw->CDB, ums->cmnd_size); @@ -1658,8 +1670,20 @@ static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; - /* Queue a request to read a Bulk-only CBW */ - _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); + // Queue a request to read a Bulk-only CBW. + if (!ums->cbw_req_queued) + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); + else + _ums_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); + + /* + * On XUSB do not allow multiple requests for CBW to be done. + * This avoids an issue with some XHCI controllers and OS combos (e.g. ASMedia and Linux/Mac OS) + * which confuse that and concatenate an old CBW request with another write request (SCSI Write) + * and create a babble error (transmit overflow). + */ + if (ums->xusb) + ums->cbw_req_queued = true; /* We will drain the buffer in software, which means we * can reuse it for the next filling. No need to advance @@ -1696,7 +1720,7 @@ static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) SK(sd), ASC(sd), ASCQ(sd), ums->lun.sense_data_info); } - /* Store and send the Bulk-only CSW */ + // Store and send the Bulk-only CSW. bulk_send_pkt_t *csw = (bulk_send_pkt_t *)bulk_ctxt->bulk_in_buf; csw->Signature = USB_BULK_CS_SIG; @@ -1712,7 +1736,7 @@ static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) { enum ums_state old_state; - /* Clear out the controller's fifos */ + // Clear out the controller's fifos. ums_flush_endpoint(bulk_ctxt->bulk_in); ums_flush_endpoint(bulk_ctxt->bulk_out); @@ -1735,7 +1759,7 @@ static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) ums->state = UMS_STATE_NORMAL; - /* Carry out any extra actions required for the exception */ + // Carry out any extra actions required for the exception. switch (old_state) { case UMS_STATE_NORMAL: @@ -1757,7 +1781,7 @@ static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) break; case UMS_STATE_EXIT: - ums->state = UMS_STATE_TERMINATED; /* Stop the thread */ + ums->state = UMS_STATE_TERMINATED; // Stop the thread. break; default: diff --git a/bdk/usb/usb_t210.h b/bdk/usb/usb_t210.h index e677a5f..3485a58 100644 --- a/bdk/usb/usb_t210.h +++ b/bdk/usb/usb_t210.h @@ -1,7 +1,7 @@ /* * Enhanced & eXtensible USB device (EDCI & XDCI) driver for Tegra X1 * - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -200,6 +200,8 @@ typedef struct _t210_usb2d_t #define XHCI_ST_IP BIT(4) #define XUSB_DEV_XHCI_RT_IMOD 0x38 #define XUSB_DEV_XHCI_PORTSC 0x3C +#define XHCI_PORTSC_CCS BIT(0) +#define XHCI_PORTSC_PED BIT(1) #define XHCI_PORTSC_PR BIT(4) #define XHCI_PORTSC_PLS_MASK (0xF << 5) #define XHCI_PORTSC_PLS_U0 (0 << 5) @@ -226,11 +228,12 @@ typedef struct _t210_usb2d_t #define XUSB_DEV_XHCI_ECPLO 0x40 #define XUSB_DEV_XHCI_ECPHI 0x44 #define XUSB_DEV_XHCI_EP_HALT 0x50 -#define XHCI_EP_HALT_DCI BIT(0) +#define XHCI_EP_HALT_DCI_EP0_IN BIT(0) #define XUSB_DEV_XHCI_EP_PAUSE 0x54 #define XUSB_DEV_XHCI_EP_RELOAD 0x58 #define XUSB_DEV_XHCI_EP_STCHG 0x5C #define XUSB_DEV_XHCI_PORTHALT 0x6C +#define XUSB_DEV_XHCI_EP_STOPPED 0x78 #define XHCI_PORTHALT_HALT_LTSSM BIT(0) #define XHCI_PORTHALT_STCHG_REQ BIT(20) #define XUSB_DEV_XHCI_CFG_DEV_FE 0x85C diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c index 95d1ed5..81d719a 100644 --- a/bdk/usb/usbd.c +++ b/bdk/usb/usbd.c @@ -1,7 +1,7 @@ /* * Enhanced USB Device (EDCI) driver for Tegra X1 * - * Copyright (c) 2019-2020 CTCaer + * Copyright (c) 2019-2021 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, @@ -1455,7 +1455,7 @@ static int _usbd_get_ep1_out_bytes_read() return (usbdaemon->ep_bytes_requested[USB_EP_BULK_OUT] - (usbdaemon->qhs[USB_EP_BULK_OUT].token >> 16)); } -int usb_device_ep1_out_reading_finish(u32 *pending_bytes) +int usb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_timeout) { usb_ep_status_t ep_status; do @@ -1504,7 +1504,7 @@ static int _usbd_get_ep1_in_bytes_written() return (usbdaemon->ep_bytes_requested[USB_EP_BULK_IN] - (usbdaemon->qhs[USB_EP_BULK_IN].token >> 16)); } -int usb_device_ep1_in_writing_finish(u32 *pending_bytes) +int usb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_timeout) { usb_ep_status_t ep_status; do diff --git a/bdk/usb/usbd.h b/bdk/usb/usbd.h index a0e4a63..86aa8fa 100644 --- a/bdk/usb/usbd.h +++ b/bdk/usb/usbd.h @@ -1,7 +1,7 @@ /* * Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1 * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -148,6 +148,7 @@ typedef enum _usb_error_t XUSB_ERROR_INVALID_EP = USB_ERROR_XFER_ERROR, // From 2. XUSB_ERROR_XFER_BULK_IN_RESIDUE = 7, XUSB_ERROR_INVALID_CYCLE = USB2_ERROR_XFER_EP_DISABLED, // From 8. + XUSB_ERROR_BABBLE_DETECTED = 50, XUSB_ERROR_SEQ_NUM = 51, XUSB_ERROR_XFER_DIR = 52, XUSB_ERROR_PORT_CFG = 54 @@ -175,9 +176,9 @@ typedef struct _usb_ops_t int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32); int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *); - int (*usb_device_ep1_out_reading_finish)(u32 *); + int (*usb_device_ep1_out_reading_finish)(u32 *, u32); int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, u32); - int (*usb_device_ep1_in_writing_finish)(u32 *); + int (*usb_device_ep1_in_writing_finish)(u32 *, u32); bool (*usb_device_get_suspended)(); bool (*usb_device_get_port_in_sleep)(); } usb_ops_t; diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c index 4beefcd..0f68ec7 100644 --- a/bdk/usb/xusbd.c +++ b/bdk/usb/xusbd.c @@ -1,7 +1,7 @@ /* * eXtensible USB Device driver (XDCI) for Tegra X1 * - * Copyright (c) 2020 CTCaer + * Copyright (c) 2020-2021 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, @@ -368,7 +368,7 @@ typedef struct _xusbd_controller_t event_trb_t *event_dequeue_ptr; u32 event_ccs; u32 device_state; - u32 bytes_remaining[2]; + u32 tx_bytes[2]; u32 tx_count[2]; u32 ctrl_seq_num; u32 config_num; @@ -881,7 +881,7 @@ int xusb_device_init() _xusbd_init_device_clocks(); // Enable AHB redirect for access to IRAM for Event/EP ring buffers. - mc_enable_ahb_redirect(); // Can be skipped if IRAM is not used. + mc_enable_ahb_redirect(false); // Can be skipped if IRAM is not used. // Enable XUSB device IPFS. XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI; @@ -927,7 +927,7 @@ int xusb_device_init() return USB_RES_OK; } -static int _xusb_queue_trb(int ep_idx, void *trb, bool ring_doorbell) +static int _xusb_queue_trb(u32 ep_idx, void *trb, bool ring_doorbell) { int res = USB_RES_OK; data_trb_t *next_trb; @@ -1073,7 +1073,7 @@ static int _xusb_issue_normal_trb(u8 *buf, u32 len, usb_dir_t direction) normal_trb_t trb = {0}; _xusb_create_normal_trb(&trb, buf, len, direction); - int ep_idx = USB_EP_BULK_IN; + u32 ep_idx = USB_EP_BULK_IN; if (direction == USB_DIR_OUT) ep_idx = USB_EP_BULK_OUT; int res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL); @@ -1100,19 +1100,32 @@ static int _xusb_issue_data_trb(u8 *buf, u32 len, usb_dir_t direction) int xusb_set_ep_stall(u32 endpoint, int ep_stall) { - int ep_idx = BIT(endpoint); + u32 ep_mask = BIT(endpoint); if (ep_stall) - XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_idx; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask; else - XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_idx; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_mask; // Wait for EP status to change. - int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_idx, ep_idx, 1000); + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000); if (res) return res; // Clear status change. - XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_idx; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask; + + return USB_RES_OK; +} + +static int _xusb_wait_ep_stopped(u32 endpoint) +{ + u32 ep_mask = BIT(endpoint); + + // Wait for EP status to change. + _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STOPPED, ep_mask, ep_mask, 1000); + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STOPPED) = ep_mask; return USB_RES_OK; } @@ -1158,20 +1171,27 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb) return _xusb_issue_status_trb(USB_DIR_OUT); else if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS) { - if (usbd_xotg->device_state == XUSB_ADDRESSED_STS_WAIT) + switch (usbd_xotg->device_state) + { + case XUSB_ADDRESSED_STS_WAIT: usbd_xotg->device_state = XUSB_ADDRESSED; - else if (usbd_xotg->device_state == XUSB_CONFIGURED_STS_WAIT) + break; + case XUSB_CONFIGURED_STS_WAIT: usbd_xotg->device_state = XUSB_CONFIGURED; - else if (usbd_xotg->device_state == XUSB_LUN_CONFIGURED_STS_WAIT) + break; + case XUSB_LUN_CONFIGURED_STS_WAIT: usbd_xotg->device_state = XUSB_LUN_CONFIGURED; - else if (usbd_xotg->device_state == XUSB_HID_CONFIGURED_STS_WAIT) + break; + case XUSB_HID_CONFIGURED_STS_WAIT: usbd_xotg->device_state = XUSB_HID_CONFIGURED; + break; + } } break; case USB_EP_BULK_IN: - usbd_xotg->bytes_remaining[USB_DIR_IN] -= trb->trb_tx_len; - if (usbd_xotg->tx_count[USB_DIR_IN])/////////// + usbd_xotg->tx_bytes[USB_DIR_IN] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_IN]) usbd_xotg->tx_count[USB_DIR_IN]--; // If bytes remaining for a Bulk IN transfer, return error. @@ -1181,8 +1201,8 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb) case USB_EP_BULK_OUT: // If short packet and Bulk OUT, it's not an error because we prime EP for 4KB. - usbd_xotg->bytes_remaining[USB_DIR_OUT] -= trb->trb_tx_len; - if (usbd_xotg->tx_count[USB_DIR_OUT])/////////// + usbd_xotg->tx_bytes[USB_DIR_OUT] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_OUT]) usbd_xotg->tx_count[USB_DIR_OUT]--; break; } @@ -1196,6 +1216,11 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb) xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL); return USB_RES_OK; */ + case XUSB_COMP_BABBLE_DETECTED_ERROR: + _xusb_wait_ep_stopped(trb->ep_id); + xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL); + return XUSB_ERROR_BABBLE_DETECTED; + case XUSB_COMP_CTRL_DIR_ERROR: return XUSB_ERROR_XFER_DIR; @@ -1216,11 +1241,52 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb) static int _xusb_handle_port_change() { - u32 res = USB_RES_OK; u32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); u32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + u32 clear_mask = XHCI_PORTSC_CEC | XHCI_PORTSC_PLC | XHCI_PORTSC_PRC | XHCI_PORTSC_WRC | XHCI_PORTSC_CSC; - // Connect status change (CSC). + // Port reset (PR). + if (status & XHCI_PORTSC_PR) + { + //! TODO: + // XHCI_PORTSC_PR: device_state = XUSB_RESET + + //_disable_usb_wdt4(); + } + + // Port Reset Change (PRC). + if (status & XHCI_PORTSC_PRC) + { + // Clear PRC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_PRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Warm Port Reset (WPR). + if (status & XHCI_PORTSC_WPR) + { + //_disable_usb_wdt4(); + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + + //! TODO: XHCI_PORTSC_WPR: device_state = XUSB_RESET + } + + // Warm Port Reset Change (WRC). + if (status & XHCI_PORTSC_WRC) + { + // Clear WRC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_WRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Reread port status to handle more changes. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + + // Connect Status Change (CSC). if (status & XHCI_PORTSC_CSC) { //! TODO: Check CCS. @@ -1238,90 +1304,64 @@ static int _xusb_handle_port_change() volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN]; ep_ctxt->avg_trb_len = 8; ep_ctxt->max_packet_size = 64; + //! TODO: If super speed is supported, ep context reload, unpause and unhalt must happen. } // Clear CSC bit. + status &= ~clear_mask; status |= XHCI_PORTSC_CSC; XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; } - // Port reset (PR), Port reset change (PRC). - if (status & XHCI_PORTSC_PR || status & XHCI_PORTSC_PRC) - { - //! TODO: - // XHCI_PORTSC_PR: device_state = XUSB_RESET - - //_disable_usb_wdt4(); - - //res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // unpatched0 - // if (res) return res; - _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // patched0 - - // Clear PRC bit. - status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PRC; - XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PRC; - } - - // Warm Port Reset (WPR), Warm Port Reset Change (WRC). - if (status & XHCI_PORTSC_WPR || status & XHCI_PORTSC_WRC) - { - XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; - (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); - res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_WRC, XHCI_PORTSC_WRC, 1000); - - // Clear WRC bit. - status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_WRC; - XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_WRC; - - //! TODO: WPR: device_state = XUSB_RESET - } - // Handle Config Request (STCHG_REQ). if (halt & XHCI_PORTHALT_STCHG_REQ) { - // Clear Link Training Status. - status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) & ~XHCI_PORTHALT_HALT_LTSSM; + // Clear Link Training Status and pending request/reject. XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); } + // Reread port status to handle more changes. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + // Port link state change (PLC). if (status & XHCI_PORTSC_PLC) { - //! WAR: Sometimes port speed changes without a CSC event. Set again. - usbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10; - - // check PLS - // if U3 + // check XHCI_PORTSC_PLS_MASK + // if XHCI_PORTSC_PLS_U3 // device_state = XUSB_SUSPENDED - // else if U0 and XUSB_SUSPENDED + // else if XHCI_PORTSC_PLS_U0 and XUSB_SUSPENDED // val = XUSB_DEV_XHCI_EP_PAUSE // XUSB_DEV_XHCI_EP_PAUSE = 0 // XUSB_DEV_XHCI_EP_STCHG = val; // Clear PLC bit. - status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PLC; - XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PLC; + status &= ~clear_mask; + status |= XHCI_PORTSC_PLC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; } // Port configuration link error (CEC). if (status & XHCI_PORTSC_CEC) { - XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_CEC; - res = XUSB_ERROR_PORT_CFG; + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + status &= ~clear_mask; + status |= XHCI_PORTSC_CEC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + + return XUSB_ERROR_PORT_CFG; } - return res; + return USB_RES_OK; } -static int _xusb_handle_get_ep_status(usb_ctrl_setup_t *ctrl_setup) +static int _xusb_handle_get_ep_status(u32 ep_idx) { + u32 ep_mask = BIT(ep_idx); static u8 xusb_ep_status_descriptor[2] = {0}; - // Get EP context pointer. - volatile xusb_ep_ctx_t *ep_ctxt = (volatile xusb_ep_ctx_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) & 0xFFFFFFF0); - ep_ctxt = &ep_ctxt[ctrl_setup->wIndex]; - - xusb_ep_status_descriptor[0] = (ep_ctxt->ep_state == EP_HALTED) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK; + xusb_ep_status_descriptor[0] = + (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) & ep_mask) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK; return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN); } @@ -1536,8 +1576,9 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup) //gfx_printf("ctrl: %02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); - XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI; - u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI, 0, 1000); + // Unhalt EP0 IN. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI_EP0_IN; + u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI_EP0_IN, 0, 1000); if (res) return res; @@ -1557,14 +1598,33 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup) case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) { - if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + if (_bRequest == USB_REQUEST_CLEAR_FEATURE || _bRequest == USB_REQUEST_SET_FEATURE) { - xusb_set_ep_stall(_wIndex, USB_EP_CFG_CLEAR); - return _xusb_issue_status_trb(USB_DIR_IN); - } - else if (_bRequest == USB_REQUEST_SET_FEATURE) - { - xusb_set_ep_stall(_wIndex, USB_EP_CFG_STALL); + u32 ep = 0; + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + ep = XUSB_EP_CTRL_OUT; + break; + case USB_EP_ADDR_CTRL_IN: + ep = XUSB_EP_CTRL_IN; + break; + case USB_EP_ADDR_BULK_OUT: + ep = USB_EP_BULK_OUT; + break; + case USB_EP_ADDR_BULK_IN: + ep = USB_EP_BULK_IN; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + xusb_set_ep_stall(ep, USB_EP_CFG_CLEAR); + else if (_bRequest == USB_REQUEST_SET_FEATURE) + xusb_set_ep_stall(ep, USB_EP_CFG_STALL); + return _xusb_issue_status_trb(USB_DIR_IN); } } @@ -1631,7 +1691,28 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup) case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): if (_bRequest == USB_REQUEST_GET_STATUS) - return _xusb_handle_get_ep_status(ctrl_setup); + { + u32 ep = 0; + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + ep = XUSB_EP_CTRL_OUT; + break; + case USB_EP_ADDR_CTRL_IN: + ep = XUSB_EP_CTRL_IN; + break; + case USB_EP_ADDR_BULK_OUT: + ep = USB_EP_BULK_OUT; + break; + case USB_EP_ADDR_BULK_IN: + ep = USB_EP_BULK_IN; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + return _xusb_handle_get_ep_status(ep); + } ep_stall = true; break; @@ -1821,6 +1902,7 @@ int xusb_device_enumerate(usb_gadget_type gadget) return USB_RES_OK; } +//! TODO: Do a full deinit. void xusb_end(bool reset_ep, bool only_controller) { CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS); @@ -1855,7 +1937,7 @@ int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries) int res = USB_RES_OK; usbd_xotg->tx_count[USB_DIR_OUT] = 0; - usbd_xotg->bytes_remaining[USB_DIR_OUT] = len; + usbd_xotg->tx_bytes[USB_DIR_OUT] = len; _xusb_issue_normal_trb(buf, len, USB_DIR_OUT); usbd_xotg->tx_count[USB_DIR_OUT]++; @@ -1865,7 +1947,7 @@ int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries) res = _xusb_ep_operation(sync_tries); if (bytes_read) - *bytes_read = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; + *bytes_read = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT]; bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); } @@ -1898,14 +1980,14 @@ int xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) return USB_RES_OK; } -int xusb_device_ep1_out_reading_finish(u32 *pending_bytes) +int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_tries) { int res = USB_RES_OK; while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) - res = _xusb_ep_operation(USB_XFER_SYNCED); // Infinite retries. + res = _xusb_ep_operation(sync_tries); // Infinite retries. if (pending_bytes) - *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT]; + *pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT]; bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); @@ -1921,7 +2003,7 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_trie int res = USB_RES_OK; usbd_xotg->tx_count[USB_DIR_IN] = 0; - usbd_xotg->bytes_remaining[USB_DIR_IN] = len; + usbd_xotg->tx_bytes[USB_DIR_IN] = len; _xusb_issue_normal_trb(buf, len, USB_DIR_IN); usbd_xotg->tx_count[USB_DIR_IN]++; @@ -1931,7 +2013,7 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_trie res = _xusb_ep_operation(sync_tries); if (bytes_written) - *bytes_written = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; + *bytes_written = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN]; } else { @@ -1947,14 +2029,14 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_trie return res; } -int xusb_device_ep1_in_writing_finish(u32 *pending_bytes) +int xusb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_tries) { int res = USB_RES_OK; while (!res && usbd_xotg->tx_count[USB_DIR_IN]) - res = _xusb_ep_operation(USB_XFER_SYNCED); // Infinite retries. + res = _xusb_ep_operation(sync_tries); // Infinite retries. if (pending_bytes) - *pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN]; + *pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN]; return res; } @@ -2010,7 +2092,7 @@ void xusb_device_get_ops(usb_ops_t *ops) ops->usbd_flush_endpoint = NULL; ops->usbd_set_ep_stall = xusb_set_ep_stall; ops->usbd_handle_ep0_ctrl_setup = xusb_handle_ep0_ctrl_setup; - ops->usbd_end = xusb_end;////////////////// + ops->usbd_end = xusb_end; ops->usb_device_init = xusb_device_init; ops->usb_device_enumerate = xusb_device_enumerate; ops->usb_device_class_send_max_lun = xusb_device_class_send_max_lun; diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 57fb509..9e6f70e 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert +* Copyright (c) 2018-2021 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, diff --git a/bdk/utils/util.c b/bdk/utils/util.c index f267236..2c21b28 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018-2020 CTCaer +* Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -30,6 +30,27 @@ extern volatile nyx_storage_t *nyx_str; +u8 bit_count(u32 val) +{ + u8 cnt = 0; + for (u32 i = 0; i < 32; i++) + { + if ((val >> i) & 1) + cnt++; + } + + return cnt; +} + +u32 bit_count_mask(u8 bits) +{ + u32 val = 0; + for (u32 i = 0; i < bits; i++) + val |= 1 << i; + + return val; +} + u32 get_tmr_s() { return RTC(APBDEV_RTC_SECONDS); diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 3503e1e..213d9cf 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2021 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, @@ -81,6 +81,9 @@ typedef struct _nyx_storage_t emc_table_t mtc_table[10]; } nyx_storage_t; +u8 bit_count(u32 val); +u32 bit_count_mask(u8 bits); + void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); u32 crc32_calc(u32 crc, const u8 *buf, u32 len); diff --git a/source/config.c b/source/config.c index 526eb55..f8ce2d9 100644 --- a/source/config.c +++ b/source/config.c @@ -38,19 +38,14 @@ void set_default_configuration() h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; - h_cfg.se_keygen_done = 0; h_cfg.backlight = 100; h_cfg.autohosoff = 0; h_cfg.autonogc = 1; h_cfg.updater2p = 0; h_cfg.bootprotect = 0; h_cfg.errors = 0; - h_cfg.eks = NULL; h_cfg.aes_slots_new = false; h_cfg.rcm_patched = fuse_check_patched_rcm(); - h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; h_cfg.emummc_force_disable = false; h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; - - sd_power_cycle_time_start = 0; } diff --git a/source/config.h b/source/config.h index bfb0b3b..03fd69b 100644 --- a/source/config.h +++ b/source/config.h @@ -17,7 +17,6 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include "hos/hos.h" #include typedef struct _hekate_config @@ -33,13 +32,10 @@ typedef struct _hekate_config u32 bootprotect; // Global temporary config. bool t210b01; - bool se_keygen_done; bool aes_slots_new; bool emummc_force_disable; bool rcm_patched; - bool sbk_set; u32 errors; - hos_eks_mbr_t *eks; } hekate_config; void set_default_configuration(); diff --git a/source/hos/hos.h b/source/hos/hos.h index 94136fa..984ae3b 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -18,122 +18,18 @@ #ifndef _HOS_H_ #define _HOS_H_ -#include "pkg1.h" -#include "pkg2.h" -#include -#include -#include -#include - -#include - -#define KB_FIRMWARE_VERSION_100_200 0 -#define KB_FIRMWARE_VERSION_300 1 -#define KB_FIRMWARE_VERSION_301 2 -#define KB_FIRMWARE_VERSION_400 3 -#define KB_FIRMWARE_VERSION_500 4 -#define KB_FIRMWARE_VERSION_600 5 -#define KB_FIRMWARE_VERSION_620 6 -#define KB_FIRMWARE_VERSION_700 7 -#define KB_FIRMWARE_VERSION_810 8 -#define KB_FIRMWARE_VERSION_900 9 -#define KB_FIRMWARE_VERSION_910 10 +#define KB_FIRMWARE_VERSION_100 0 +#define KB_FIRMWARE_VERSION_300 1 +#define KB_FIRMWARE_VERSION_301 2 +#define KB_FIRMWARE_VERSION_400 3 +#define KB_FIRMWARE_VERSION_500 4 +#define KB_FIRMWARE_VERSION_600 5 +#define KB_FIRMWARE_VERSION_620 6 +#define KB_FIRMWARE_VERSION_700 7 +#define KB_FIRMWARE_VERSION_810 8 +#define KB_FIRMWARE_VERSION_900 9 +#define KB_FIRMWARE_VERSION_910 10 #define KB_FIRMWARE_VERSION_1210 11 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 - -#define HOS_PKG11_MAGIC 0x31314B50 -#define HOS_EKS_MAGIC 0x30534B45 - -// Use official Mariko secmon when in stock. -//#define HOS_MARIKO_STOCK_SECMON - -typedef struct _exo_ctxt_t -{ - bool fs_is_510; - bool no_user_exceptions; - bool user_pmu; - bool *usb3_force; - bool *cal0_blank; - bool *cal0_allow_writes_sys; -} exo_ctxt_t; - -typedef struct _hos_eks_keys_t -{ - u8 mkk[SE_KEY_128_SIZE]; - u8 fdk[SE_KEY_128_SIZE]; -} hos_eks_keys_t; - -typedef struct _hos_eks_bis_keys_t -{ - u8 crypt[SE_KEY_128_SIZE]; - u8 tweak[SE_KEY_128_SIZE]; -} hos_eks_bis_keys_t; - -typedef struct _hos_eks_mbr_t -{ - u32 magic; - u8 enabled[5]; - u8 enabled_bis; - u8 rsvd[2]; - u32 lot0; - u8 dkg[SE_KEY_128_SIZE]; - u8 dkk[SE_KEY_128_SIZE]; - hos_eks_keys_t keys[5]; - hos_eks_bis_keys_t bis_keys[3]; -} hos_eks_mbr_t; - -static_assert(sizeof(hos_eks_mbr_t) == 304, "HOS EKS size is wrong!"); - -typedef struct _launch_ctxt_t -{ - void *keyblob; - - void *pkg1; - const pkg1_id_t *pkg1_id; - const pkg2_kernel_id_t *pkg2_kernel_id; - - void *warmboot; - u32 warmboot_size; - void *secmon; - u32 secmon_size; - void *exofatal; - u32 exofatal_size; - - void *pkg2; - u32 pkg2_size; - bool new_pkg2; - - void *kernel; - u32 kernel_size; - - link_t kip1_list; - char* kip1_patches; - - bool svcperm; - bool debugmode; - bool stock; - bool emummc_forced; - - char *fss0_main_path; - u32 fss0_hosver; - bool fss0_experimental; - bool atmosphere; - - exo_ctxt_t exo_ctx; - - ini_sec_t *cfg; -} launch_ctxt_t; - -typedef struct _merge_kip_t -{ - void *kip1; - link_t link; -} merge_kip_t; - -void hos_eks_get(); -void hos_eks_save(u32 kb); -void hos_eks_clear(u32 kb); -int hos_launch(ini_sec_t *cfg); -int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 //!TODO: Update on mkey changes. #endif diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c deleted file mode 100644 index b80c06d..0000000 --- a/source/hos/pkg2.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2020 CTCaer - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "pkg2.h" -#include -#include -#include -#include - -#include - -u32 pkg2_newkern_ini1_val; -u32 pkg2_newkern_ini1_start; -u32 pkg2_newkern_ini1_end; - -/*#include "util.h" -#define DPRINTF(...) gfx_printf(__VA_ARGS__) -#define DEBUG_PRINTING*/ -#define DPRINTF(...) - -static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) -{ - u32 size = sizeof(pkg2_kip1_t); - for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++) - size += kip1->sections[j].size_comp; - return size; -} - -void pkg2_get_newkern_info(u8 *kern_data) -{ - u32 pkg2_newkern_ini1_off = 0; - 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_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); - } - -bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) -{ - u8 *ptr; - // Check for new pkg2 type. - if (!pkg2->sec_size[PKG2_SEC_INI1]) - { - pkg2_get_newkern_info(pkg2->data); - - if (!pkg2_newkern_ini1_start) - return false; - - ptr = pkg2->data + pkg2_newkern_ini1_start; - *new_pkg2 = true; - } - else - ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL]; - - pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr; - ptr += sizeof(pkg2_ini1_t); - - for (u32 i = 0; i < ini1->num_procs; i++) - { - pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr; - pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t)); - ki->kip1 = kip1; - ki->size = _pkg2_calc_kip1_size(kip1); - list_append(info, &ki->link); - ptr += 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) -{ - u32 compClearMask = ~sectsToDecomp; - if ((ki->kip1->flags & compClearMask) == ki->kip1->flags) - return 0; // Already decompressed, nothing to do. - - pkg2_kip1_t hdr; - memcpy(&hdr, ki->kip1, sizeof(hdr)); - - unsigned int newKipSize = sizeof(hdr); - for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) - { - u32 sectCompBit = 1u << sectIdx; - // For compressed, cant get actual decompressed size without doing it, so use safe "output size". - if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) - newKipSize += hdr.sections[sectIdx].size_decomp; - else - newKipSize += hdr.sections[sectIdx].size_comp; - } - - pkg2_kip1_t* newKip = malloc(newKipSize); - unsigned char* dstDataPtr = newKip->data; - const unsigned char* srcDataPtr = ki->kip1->data; - for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) - { - u32 sectCompBit = 1u << sectIdx; - // Easy copy path for uncompressed or ones we dont want to uncompress. - if (sectIdx >= 3 || !(sectsToDecomp & sectCompBit) || !(hdr.flags & sectCompBit)) - { - unsigned int dataSize = hdr.sections[sectIdx].size_comp; - if (dataSize == 0) - continue; - - memcpy(dstDataPtr, srcDataPtr, dataSize); - srcDataPtr += dataSize; - dstDataPtr += dataSize; - continue; - } - - unsigned int compSize = hdr.sections[sectIdx].size_comp; - unsigned int outputSize = hdr.sections[sectIdx].size_decomp; - //gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize); - if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0) - { - gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); - free(newKip); - - return 1; - } - else - { - DPRINTF("Done! Decompressed size is %d!\n", outputSize); - } - hdr.sections[sectIdx].size_comp = outputSize; - srcDataPtr += compSize; - dstDataPtr += outputSize; - } - - hdr.flags &= compClearMask; - memcpy(newKip, &hdr, sizeof(hdr)); - newKipSize = dstDataPtr-(unsigned char*)(newKip); - - free(ki->kip1); - ki->kip1 = newKip; - ki->size = newKipSize; - - return 0; -} - -pkg2_hdr_t *pkg2_decrypt(void *data) -{ - u8 *pdata = (u8 *)data; - - // Skip signature. - pdata += 0x100; - - pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata; - - // Skip header. - pdata += sizeof(pkg2_hdr_t); - - // Decrypt header. - se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); - //gfx_hexdump((u32)hdr, hdr, 0x100); - - if (hdr->magic != PKG2_MAGIC) - return NULL; - - for (u32 i = 0; i < 4; i++) - { -DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]); - if (!hdr->sec_size[i]) - continue; - - se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); - //gfx_hexdump((u32)pdata, pdata, 0x100); - - pdata += hdr->sec_size[i]; - } - - return hdr; -} diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h deleted file mode 100644 index e416fba..0000000 --- a/source/hos/pkg2.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-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 . - */ - -#ifndef _PKG2_H_ -#define _PKG2_H_ - -#include -#include - -#define PKG2_MAGIC 0x31324B50 -#define PKG2_SEC_BASE 0x80000000 -#define PKG2_SEC_KERNEL 0 -#define PKG2_SEC_INI1 1 - -#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset. - -extern u32 pkg2_newkern_ini1_val; -extern u32 pkg2_newkern_ini1_start; -extern u32 pkg2_newkern_ini1_end; - -typedef struct _kernel_patch_t -{ - u32 id; - u32 off; - u32 val; - u32 *ptr; -} kernel_patch_t; - -typedef struct _pkg2_hdr_t -{ - u8 ctr[0x10]; - u8 sec_ctr[0x40]; - u32 magic; - u32 base; - u32 pad0; - u8 pkg2_ver; - u8 bl_ver; - u16 pad1; - u32 sec_size[4]; - u32 sec_off[4]; - u8 sec_sha256[0x80]; - u8 data[]; -} pkg2_hdr_t; - -typedef struct _pkg2_ini1_t -{ - u32 magic; - u32 size; - u32 num_procs; - u32 pad; -} pkg2_ini1_t; - -typedef struct _pkg2_kip1_sec_t -{ - u32 offset; - u32 size_decomp; - u32 size_comp; - u32 attrib; -} pkg2_kip1_sec_t; - -#define KIP1_NUM_SECTIONS 6 - -typedef struct _pkg2_kip1_t -{ - u32 magic; - u8 name[12]; - u64 tid; - u32 proc_cat; - u8 main_thrd_prio; - u8 def_cpu_core; - u8 res; - u8 flags; - pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS]; - u32 caps[0x20]; - u8 data[]; -} pkg2_kip1_t; - -typedef struct _pkg2_kip1_info_t -{ - pkg2_kip1_t *kip1; - u32 size; - link_t link; -} pkg2_kip1_info_t; - -typedef struct _pkg2_kernel_id_t -{ - u8 hash[8]; - kernel_patch_t *kernel_patchset; -} pkg2_kernel_id_t; - -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); -pkg2_hdr_t *pkg2_decrypt(void *data); - -#endif diff --git a/source/keys/keys.c b/source/keys/keys.c index 387ebfc..0103c26 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -23,7 +23,6 @@ #include #include "../gfx/tui.h" #include "../hos/pkg1.h" -#include "../hos/pkg2.h" #include #include #include @@ -79,21 +78,6 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); -static ALWAYS_INLINE u8 *_find_tsec_fw(const u8 *pkg1) { - const u32 tsec_fw_align = 0x100; - const u32 tsec_fw_first_instruction = 0xCF42004D; - - for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + PKG1_MAX_SIZE; pos += tsec_fw_align / sizeof(u32)) - if (*pos == tsec_fw_first_instruction) - return (u8 *)pos; - - return NULL; -} - -static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) { - return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; -} - static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { if (emummc_storage_init_mmc()) { EPRINTF("Unable to init MMC."); @@ -125,17 +109,18 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 - se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); + se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); // Relies on the Mariko KEK being properly set in slot 12 se_aes_unwrap_key(8, 12, is_dev ? &mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]); - se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); } static int _run_ams_keygen(key_derivation_ctx_t *keys) { tsec_ctxt_t tsec_ctxt; tsec_ctxt.fw = tsec_keygen; tsec_ctxt.size = sizeof(tsec_keygen); - int res = tsec_run_fw(&tsec_ctxt); + tsec_ctxt.type = TSEC_FW_TYPE_NEW; + int res = tsec_query(keys->temp_key, &tsec_ctxt); if (res) { EPRINTFARGS("ERROR %d running keygen.\n", res); @@ -149,19 +134,19 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool u32 tsec_root_key_slot = is_dev ? 11 : 13; // Derive all master keys based on current root key for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { - se_aes_crypt_block_ecb(tsec_root_key_slot, 0, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks) + se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks) se_aes_key_set(8, keys->master_kek[i + KB_FIRMWARE_VERSION_620], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) - se_aes_crypt_block_ecb(8, 0, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source); } } // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); + se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); } se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); + se_aes_crypt_block_ecb(8, DECRYPT, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); if (_key_exists(keys->temp_key)) { EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); @@ -174,7 +159,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; - if (h_cfg.sbk_set) { + if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { u8 *aes_keys = (u8 *)calloc(0x1000, 1); se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); @@ -192,13 +177,13 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); - se_aes_crypt_block_ecb(12, 0, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) - se_aes_crypt_block_ecb(14, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) + se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) + se_aes_crypt_block_ecb(14, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); - se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) + se_aes_crypt_block_ecb(7, DECRYPT, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { - se_aes_crypt_block_ecb(7, 0, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, 0, keys->device_key_4x, device_master_key_source_kek_source); + se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) + se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); } // verify keyblob is not corrupt @@ -217,7 +202,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); se_aes_key_set(7, keys->master_kek[i], sizeof(keys->master_kek[i])); if (!_key_exists(keys->master_key[i])) { - se_aes_crypt_block_ecb(7, 0, keys->master_key[i], master_key_source); + se_aes_crypt_block_ecb(7, DECRYPT, keys->master_key[i], master_key_source); } } free(keyblob_block); @@ -238,15 +223,15 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { _generate_specific_aes_key(8, keys, &keys->bis_key[0], &bis_key_sources[0], key_generation); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_ecb(8, 0, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) - se_aes_crypt_ecb(8, 0, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2); + se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) + se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2); memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); } static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_ecb(8, 0, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2); + se_aes_crypt_ecb(8, DECRYPT, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2); } } @@ -254,19 +239,19 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { _get_device_key(8, keys, keys->temp_key, 0); _generate_kek(8, save_mac_kek_source, keys->temp_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->save_mac_key, save_mac_key_source); } if (_key_exists(keys->master_key[0])) { for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); + se_aes_crypt_block_ecb(8, DECRYPT, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); } } @@ -276,11 +261,11 @@ static void _derive_master_key_per_generation_keys(key_derivation_ctx_t *keys) { continue; for (u32 j = 0; j < 3; j++) { _generate_kek(8, key_area_key_sources[j], keys->master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, keys->key_area_key[j][i], aes_key_generation_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->key_area_key[j][i], aes_key_generation_source); } se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->package2_key[i], package2_key_source); - se_aes_crypt_block_ecb(8, 0, keys->titlekek[i], titlekek_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->package2_key[i], package2_key_source); + se_aes_crypt_block_ecb(8, DECRYPT, keys->titlekek[i], titlekek_source); } } @@ -478,7 +463,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return false; } - se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); + se_aes_xts_crypt(1, 0, DECRYPT, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; if (cal0->magic != MAGIC_CAL0) { @@ -496,7 +481,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; _get_device_key(7, keys, temp_device_key, keypair_generation); _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source); + se_aes_crypt_block_ecb(7, DECRYPT, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source); memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key)); } else { memcpy(keys->temp_key, keys->eticket_rsa_kek, sizeof(keys->temp_key)); @@ -594,21 +579,21 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { for (u32 ks = start; ks < start + count; ks++) { // Check if key is as expected if (ks < ARRAY_SIZE(mariko_key_vectors)) { - se_aes_crypt_block_ecb(ks, 0, &data[0], mariko_key_vectors[ks]); + se_aes_crypt_block_ecb(ks, DECRYPT, &data[0], mariko_key_vectors[ks]); if (_key_exists(data)) { continue; } } // Encrypt zeros with complete key - se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros); + se_aes_crypt_block_ecb(ks, ENCRYPT, &data[3 * AES_128_KEY_SIZE], zeros); // We only need to overwrite 3 of the dwords of the key for (u32 i = 0; i < 3; i++) { // Overwrite ith dword of key with zeros se_aes_key_partial_set(ks, i, 0); // Encrypt zeros with more of the key zeroed out - se_aes_crypt_block_ecb(ks, 1, &data[(2 - i) * AES_128_KEY_SIZE], zeros); + se_aes_crypt_block_ecb(ks, ENCRYPT, &data[(2 - i) * AES_128_KEY_SIZE], zeros); } // Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot @@ -785,7 +770,7 @@ static bool _check_keyslot_access() { u8 test_data[AES_128_KEY_SIZE] = {0}; const u8 test_ciphertext[AES_128_KEY_SIZE] = {0}; se_aes_key_set(8, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); - se_aes_crypt_block_ecb(8, 0, test_data, test_ciphertext); + se_aes_crypt_block_ecb(8, DECRYPT, test_data, test_ciphertext); return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; } @@ -944,14 +929,14 @@ static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void _get_device_key(ks, keys, keys->temp_key, key_generation); se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_ecb(ks, 0, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) + se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) } else { _get_secure_data(keys, out_key); } } static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision) { - if (revision == KB_FIRMWARE_VERSION_100_200 && !h_cfg.t210b01) { + if (revision == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) { memcpy(out_device_key, keys->device_key, AES_128_KEY_SIZE); return; } @@ -963,11 +948,11 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device } u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; se_aes_key_set(ks, keys->device_key_4x, AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(ks, 0, temp_key, device_master_key_source_sources[revision]); + se_aes_crypt_block_ecb(ks, DECRYPT, temp_key, device_master_key_source_sources[revision]); se_aes_key_set(ks, keys->master_key[0], AES_128_KEY_SIZE); const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[revision] : device_master_kek_sources_dev[revision]; se_aes_unwrap_key(ks, ks, kek_source); - se_aes_crypt_block_ecb(ks, 0, out_device_key, temp_key); + se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key); } static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { diff --git a/source/main.c b/source/main.c index 1eea1fb..f9f2e19 100644 --- a/source/main.c +++ b/source/main.c @@ -23,6 +23,7 @@ #include #include #include "gfx/tui.h" +#include "hos/pkg1.h" #include #include #include diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 1362274..a6f51b9 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -160,7 +160,7 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool force } // Encrypt and write. - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 1, tweak, true, sector_index_in_cluster, cluster, bis_cache->emmc_buffer, buff, count * NX_EMMC_BLOCKSIZE) || + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, ENCRYPT, tweak, true, sector_index_in_cluster, cluster, bis_cache->emmc_buffer, buff, count * NX_EMMC_BLOCKSIZE) || !nx_emmc_part_write(&emmc_storage, system_part, sector, count, bis_cache->emmc_buffer) ) return 1; // R/W error. @@ -227,7 +227,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) // Read and decrypt the whole cluster the sector resides in. if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, bis_cache->emmc_buffer) || - !_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, bis_cache->emmc_buffer, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE) + !_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, DECRYPT, cache_tweak, true, 0, cluster, bis_cache->emmc_buffer, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE) ) return 1; // R/W error. @@ -257,7 +257,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) tweak_exp = sector_index_in_cluster; // Maximum one cluster (1 XTS crypto block 16KB). - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->emmc_buffer, count * NX_EMMC_BLOCKSIZE)) + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, DECRYPT, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->emmc_buffer, count * NX_EMMC_BLOCKSIZE)) return 1; // R/W error. prev_sector = sector + count - 1; From 8377cf0c18cac479143a15a0ff6b25974bba9747 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 28 Aug 2021 15:28:29 -0600 Subject: [PATCH 120/166] Remove all pkg1 code and key generation display --- source/hos/hos.h | 2 ++ source/hos/pkg1.c | 68 ------------------------------------- source/hos/pkg1.h | 47 ------------------------- source/keys/key_sources.inl | 13 ++++--- source/keys/keys.c | 43 +++++------------------ source/main.c | 44 ++---------------------- 6 files changed, 21 insertions(+), 196 deletions(-) delete mode 100644 source/hos/pkg1.c delete mode 100644 source/hos/pkg1.h diff --git a/source/hos/hos.h b/source/hos/hos.h index 984ae3b..ef83f5f 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -18,6 +18,8 @@ #ifndef _HOS_H_ #define _HOS_H_ +#define KEYBLOB_OFFSET 0x180000 + #define KB_FIRMWARE_VERSION_100 0 #define KB_FIRMWARE_VERSION_300 1 #define KB_FIRMWARE_VERSION_301 2 diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c deleted file mode 100644 index 1f2942a..0000000 --- a/source/hos/pkg1.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 st4rk - * Copyright (c) 2018-2021 CTCaer - * Copyright (c) 2018 balika011 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "pkg1.h" -#include "hos.h" -#include -#include - -static const pkg1_id_t _pkg1_ids[] = { - { "20161121", 0 }, //1.0.0 - { "20170210", 0 }, //2.0.0 - 2.3.0 - { "20170519", 1 }, //3.0.0 - { "20170710", 2 }, //3.0.1 - 3.0.2 - { "20170921", 3 }, //4.0.0 - 4.1.0 - { "20180220", 4 }, //5.0.0 - 5.1.0 - { "20180802", 5 }, //6.0.0 - 6.1.0 - { "20181107", 6 }, //6.2.0 - { "20181218", 7 }, //7.0.0 - { "20190208", 7 }, //7.0.1 - { "20190314", 7 }, //8.0.0 - 8.0.1 - { "20190531", 8 }, //8.1.0 - 8.1.1 - { "20190809", 9 }, //9.0.0 - 9.0.1 - { "20191021", 10}, //9.1.0 - 9.2.0 - { "20200303", 10}, //10.0.0 - 10.2.0 - { "20201030", 10}, //11.0.0 - 11.0.1 - { "20210129", 10}, //12.0.0 - 12.0.1 - { "20210422", 10}, //12.0.2 - 12.0.3 - { "20210607", 11}, //12.1.0 - { NULL } //End. -}; - -const pkg1_id_t *pkg1_identify(u8 *pkg1) -{ - for (u32 i = 0; i < ARRAY_SIZE(_pkg1_ids); i++) - if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 8)) - return &_pkg1_ids[i]; - - char build_date[15]; - memcpy(build_date, (char *)(pkg1 + 0x10), 14); - build_date[14] = 0; - EPRINTFARGS("Found pkg1 ('%s').", build_date); - - if (*(pkg1 + 0xE) != KB_FIRMWARE_VERSION_MAX + 1) { - EPRINTF("Unsupported key generation!\nLockpick_RCM must be updated for support!"); - return NULL; - } - - EPRINTF("Contact if master key derivation fails."); - return &_pkg1_ids[ARRAY_SIZE(_pkg1_ids)-1]; -} diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h deleted file mode 100644 index 81bef20..0000000 --- a/source/hos/pkg1.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _PKG1_H_ -#define _PKG1_H_ - -#include - -#define PKG1_MAX_SIZE 0x40000 -#define PKG1_OFFSET 0x100000 -#define KEYBLOB_OFFSET 0x180000 - -typedef struct _bl_hdr_t210b01_t -{ - u8 aes_mac[0x10]; - u8 rsa_sig[0x100]; - u8 salt[0x20]; - u8 sha256[0x20]; - u32 version; - u32 size; - u32 load_addr; - u32 entrypoint; - u8 rsvd[0x10]; -} bl_hdr_t210b01_t; - -typedef struct _pkg1_id_t -{ - const char *id; - u32 kb; -} pkg1_id_t; - -const pkg1_id_t *pkg1_identify(u8 *pkg1); - -#endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 560efac..3a65539 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -28,6 +28,7 @@ static const u8 keyblob_key_sources[][0x10] __attribute__((aligned(4))) = { {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 }; +//!TODO: Update on mkey changes. static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] __attribute__((aligned(4))) = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 @@ -37,6 +38,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0 }; +//!TODO: Update on mkey changes. static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ @@ -52,6 +54,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ }; +//!TODO: Update on mkey changes. static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { {0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */ {0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */ @@ -124,7 +127,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, // 9.0.0. {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. -}; +}; //!TODO: Update on mkey changes. static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. {0xCC, 0x97, 0x4C, 0x46, 0x2A, 0x0C, 0xB0, 0xA6, 0xC9, 0xC0, 0xB7, 0xBE, 0x30, 0x2E, 0xC3, 0x68}, // 6.2.0. @@ -133,7 +136,7 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x82, 0x72, 0x91, 0x65, 0x40, 0x3B, 0x9D, 0x66, 0x60, 0xD0, 0x1B, 0x3D, 0x4D, 0xA5, 0x70, 0xE1}, // 9.0.0. {0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE}, // 9.1.0. {0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0. -}; +}; //!TODO: Update on mkey changes. static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ @@ -145,7 +148,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ -}; +}; //!TODO: Update on mkey changes. // from ES static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { @@ -171,7 +174,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ -}; +}; //!TODO: Update on mkey changes. static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */ @@ -183,7 +186,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */ {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ -}; +}; //!TODO: Update on mkey changes. // from SPL static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { diff --git a/source/keys/keys.c b/source/keys/keys.c index 0103c26..e8d8d49 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -22,7 +22,7 @@ #include #include #include "../gfx/tui.h" -#include "../hos/pkg1.h" +#include "../hos/hos.h" #include #include #include @@ -78,35 +78,6 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); -static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { - if (emummc_storage_init_mmc()) { - EPRINTF("Unable to init MMC."); - return NULL; - } - TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); - - // Read package1. - u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); - if (!emummc_storage_set_mmc_partition(EMMC_BOOT0)) { - EPRINTF("Unable to set partition."); - return NULL; - } - if (!emummc_storage_read(PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1)) { - EPRINTF("Unable to read pkg1."); - return NULL; - } - - u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. - *pkg1_id = pkg1_identify(pkg1 + pk1_offset); - if (!*pkg1_id) { - EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); - gfx_hexdump(0, pkg1, 0x20); - return NULL; - } - - return pkg1; -} - static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); @@ -791,12 +762,16 @@ static void _derive_keys() { u32 start_whole_operation_time = get_tmr_us(); - const pkg1_id_t *pkg1_id; - u8 *pkg1 = _read_pkg1(&pkg1_id); - if (!pkg1) { + if (emummc_storage_init_mmc()) { + EPRINTF("Unable to init MMC."); + return; + } + TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); + + if (!emummc_storage_set_mmc_partition(EMMC_BOOT0)) { + EPRINTF("Unable to set partition."); return; } - free(pkg1); bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; diff --git a/source/main.c b/source/main.c index f9f2e19..4487321 100644 --- a/source/main.c +++ b/source/main.c @@ -23,7 +23,6 @@ #include #include #include "gfx/tui.h" -#include "hos/pkg1.h" #include #include #include @@ -300,8 +299,8 @@ power_state_t STATE_REBOOT_RCM = REBOOT_RCM; power_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES; ment_t ment_top[] = { - MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), - MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), + MDEF_HANDLER("Dump from SysNAND", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump from EmuNAND", dump_emunand, COLOR_ORANGE), MDEF_CAPTION("---------------", COLOR_YELLOW), MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), MDEF_CAPTION("---------------", COLOR_BLUE), @@ -313,42 +312,6 @@ ment_t ment_top[] = { menu_t menu_top = { ment_top, NULL, 0, 0 }; -void _get_key_generations(char *sysnand_label, char *emunand_label) -{ - sdmmc_t sdmmc; - sdmmc_storage_t storage; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); - u8 *pkg1 = (u8 *)malloc(PKG1_MAX_SIZE); - sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0); - sdmmc_storage_read(&storage, PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); - sdmmc_storage_end(&storage); - - u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset); - if (pkg1_id) { - s_printf(sysnand_label + 36, "% 3d", pkg1_id->kb); - ment_top[0].caption = sysnand_label; - if (h_cfg.emummc_force_disable) - { - free(pkg1); - return; - } - } - - emummc_storage_init_mmc(); - memset(pkg1, 0, PKG1_MAX_SIZE); - emummc_storage_set_mmc_partition(EMMC_BOOT0); - emummc_storage_read(PKG1_OFFSET / NX_EMMC_BLOCKSIZE, PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE, pkg1); - emummc_storage_end(); - - pkg1_id = pkg1_identify(pkg1 + pk1_offset); - if (pkg1_id) { - s_printf(emunand_label + 36, "% 3d", pkg1_id->kb); - free(pkg1); - ment_top[1].caption = emunand_label; - } -} - extern void pivot_stack(u32 stack_top); void ipl_main() @@ -417,9 +380,6 @@ void ipl_main() ment_top[6].data = &STATE_REBOOT_FULL; } - // Update key generations listed in menu. - _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); - while (true) tui_do_menu(&menu_top); From 2a8184960a0e6d43bff7f2edc5f82b93b47f34cc Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 28 Aug 2021 15:29:17 -0600 Subject: [PATCH 121/166] Bump version to v1.9.4 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 5175031..488bd80 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,4 +1,4 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 3 +LPVERSION_BUGFX := 4 From faaf2166e946474004556cbb7285354140024a71 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 29 Aug 2021 09:22:34 -0600 Subject: [PATCH 122/166] Only save one key set on Mariko, save master_keks --- source/keys/keys.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index e8d8d49..7d3cddc 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -81,9 +81,13 @@ static bool _test_key_pair(const void *E, const void *D, const void *N); static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); - // Relies on the Mariko KEK being properly set in slot 12 - se_aes_unwrap_key(8, 12, is_dev ? &mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]); - se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); + // Derive all master keys based on Mariko KEK + for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) { + // Relies on the Mariko KEK being properly set in slot 12 + se_aes_crypt_block_ecb(12, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); // mkek = unwrap(mariko_kek, mariko_kek_source) + se_aes_key_set(8, keys->master_kek[i], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) + se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i], master_key_source); + } } static int _run_ams_keygen(key_derivation_ctx_t *keys) { @@ -226,7 +230,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { } } -static void _derive_master_key_per_generation_keys(key_derivation_ctx_t *keys) { +static void _derive_per_generation_keys(key_derivation_ctx_t *keys) { for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) { if (!_key_exists(keys->master_key[i])) continue; @@ -811,12 +815,12 @@ static void _derive_keys() { _derive_non_unique_keys(&prod_keys, is_dev); _derive_non_unique_keys(&dev_keys, is_dev); - _derive_master_key_per_generation_keys(&prod_keys); - _derive_master_key_per_generation_keys(&dev_keys); + _derive_per_generation_keys(&prod_keys); + _derive_per_generation_keys(&dev_keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; - // BIS key for SYSTEM partition + // Requires BIS key for SYSTEM partition if (_key_exists(keys->bis_key[2])) { _derive_emmc_keys(keys, titlekey_buffer); } else { @@ -825,9 +829,16 @@ static void _derive_keys() { end_time = get_tmr_us(); gfx_printf("%kLockpick totally done in %d us\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); - _save_keys_to_sd(&prod_keys, titlekey_buffer, false); - _key_count = 0; - _save_keys_to_sd(&dev_keys, NULL, true); + + if (h_cfg.t210b01) { + // On Mariko, save only relevant key set + _save_keys_to_sd(keys, titlekey_buffer, is_dev); + } else { + // On Erista, save both prod and dev key sets + _save_keys_to_sd(&prod_keys, titlekey_buffer, false); + _key_count = 0; + _save_keys_to_sd(&dev_keys, NULL, true); + } } void dump_keys() { From 705bb7c066c01a8fd1c1e6174a5e74323ee83937 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 29 Aug 2021 09:49:36 -0600 Subject: [PATCH 123/166] Do not require MMC mount to dump keys --- source/keys/keys.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 7d3cddc..cafc566 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -131,8 +131,8 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); - encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; + bool have_keyblobs = true; if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { u8 *aes_keys = (u8 *)calloc(0x1000, 1); @@ -146,10 +146,16 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); } - if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { + if (!emmc_storage.initialized) { + have_keyblobs = false; + } else if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblobs."); + have_keyblobs = false; + } else { + have_keyblobs = true; } + encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) @@ -161,6 +167,10 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); } + if (!have_keyblobs) { + continue; + } + // verify keyblob is not corrupt se_aes_key_set(10, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i])); se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); @@ -547,7 +557,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { } u32 pos = 0; - u32 zeros[4] = {0}; + u32 zeros[AES_128_KEY_SIZE / 4] = {0}; u8 *data = malloc(4 * AES_128_KEY_SIZE); char *text_buffer = calloc(1, 0x100 * count); @@ -768,13 +778,13 @@ static void _derive_keys() { if (emummc_storage_init_mmc()) { EPRINTF("Unable to init MMC."); - return; + } else { + TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); } - TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); - if (!emummc_storage_set_mmc_partition(EMMC_BOOT0)) { + if (emmc_storage.initialized && !emummc_storage_set_mmc_partition(EMMC_BOOT0)) { EPRINTF("Unable to set partition."); - return; + emummc_storage_end(); } bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; @@ -821,7 +831,9 @@ static void _derive_keys() { titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; // Requires BIS key for SYSTEM partition - if (_key_exists(keys->bis_key[2])) { + if (!emmc_storage.initialized) { + EPRINTF("eMMC not initialized.\nSkipping SD seed and titlekeys."); + } else if (_key_exists(keys->bis_key[2])) { _derive_emmc_keys(keys, titlekey_buffer); } else { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); @@ -861,7 +873,9 @@ void dump_keys() { // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; emu_cfg.enabled = !h_cfg.emummc_force_disable; - emummc_storage_end(&emmc_storage); + if (emmc_storage.initialized) { + emummc_storage_end(); + } gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); gfx_clear_grey(0x1B); From e041330ed99412c43e93a4a3acf27bae44535d22 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 30 Aug 2021 21:32:57 -0600 Subject: [PATCH 124/166] Retry tsec keygen on failure --- source/keys/keys.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index cafc566..159ea3f 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -95,13 +95,17 @@ static int _run_ams_keygen(key_derivation_ctx_t *keys) { tsec_ctxt.fw = tsec_keygen; tsec_ctxt.size = sizeof(tsec_keygen); tsec_ctxt.type = TSEC_FW_TYPE_NEW; - int res = tsec_query(keys->temp_key, &tsec_ctxt); - if (res) { - EPRINTFARGS("ERROR %d running keygen.\n", res); + u32 retries = 0; + while (tsec_query(keys->temp_key, &tsec_ctxt) < 0) { + retries++; + if (retries > 15) { + EPRINTF("Failed to run keygen."); + return -1; + } } - return res; + return 0; } static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool is_dev) { @@ -799,7 +803,6 @@ static void _derive_keys() { } else { int res = _run_ams_keygen(keys); if (res) { - EPRINTF("Unable to run keygen."); return; } From 8fa8941cd26e2479db03c0e443d4c6f280de14e0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 30 Aug 2021 21:33:26 -0600 Subject: [PATCH 125/166] Fix plural name of bis_key_source in key file --- source/keys/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 159ea3f..65f582e 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -643,7 +643,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(aes_key_generation_source); SAVE_KEY(bis_kek_source); SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0); - SAVE_KEY_FAMILY(bis_key_sources, 0); + SAVE_KEY_FAMILY_VAR(bis_key_source, bis_key_sources, 0); SAVE_KEY_VAR(device_key, keys->device_key); SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); From c1436648dfc83c036b52283d48c491e2fb27dabb Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 5 Sep 2021 14:08:35 -0600 Subject: [PATCH 126/166] Lower RAM speed while not doing keygen --- bdk/utils/types.h | 4 ++++ source/keys/keys.c | 18 ++++++++++++++++++ source/main.c | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bdk/utils/types.h b/bdk/utils/types.h index 9e6f70e..a56b202 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -18,6 +18,8 @@ #ifndef _TYPES_H_ #define _TYPES_H_ +#include + #define NULL ((void *)0) #define ALWAYS_INLINE inline __attribute__((always_inline)) @@ -105,6 +107,8 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t }; } boot_cfg_t; +static_assert(sizeof(boot_cfg_t) == 0x84, "Boot CFG size is wrong!"); + typedef struct __attribute__((__packed__)) _reloc_meta_t { u32 start; diff --git a/source/keys/keys.c b/source/keys/keys.c index 65f582e..f3c0d7a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -769,10 +769,14 @@ static void _derive_keys() { f_unlink("sd:/switch/partialaes.keys"); } + minerva_periodic_training(); + if (h_cfg.t210b01) { _save_mariko_partial_keys(0, 12, false); } + minerva_periodic_training(); + if (!_check_keyslot_access()) { EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip."); return; @@ -786,6 +790,8 @@ static void _derive_keys() { TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); } + minerva_periodic_training(); + if (emmc_storage.initialized && !emummc_storage_set_mmc_partition(EMMC_BOOT0)) { EPRINTF("Unable to set partition."); emummc_storage_end(); @@ -799,6 +805,7 @@ static void _derive_keys() { // Master key derivation if (h_cfg.t210b01) { _derive_master_key_mariko(keys, is_dev); + minerva_periodic_training(); _derive_master_keys_from_latest_key(keys, is_dev); } else { int res = _run_ams_keygen(keys); @@ -814,7 +821,9 @@ static void _derive_keys() { free(aes_keys); _derive_master_keys_from_latest_key(&prod_keys, false); + minerva_periodic_training(); _derive_master_keys_from_latest_key(&dev_keys, true); + minerva_periodic_training(); _derive_keyblob_keys(keys); } @@ -824,11 +833,16 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); + minerva_periodic_training(); _derive_misc_keys(keys, is_dev); + minerva_periodic_training(); _derive_non_unique_keys(&prod_keys, is_dev); + minerva_periodic_training(); _derive_non_unique_keys(&dev_keys, is_dev); + minerva_periodic_training(); _derive_per_generation_keys(&prod_keys); + minerva_periodic_training(); _derive_per_generation_keys(&dev_keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; @@ -857,6 +871,8 @@ static void _derive_keys() { } void dump_keys() { + minerva_change_freq(FREQ_1600); + display_backlight_brightness(h_cfg.backlight, 1000); gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); @@ -879,6 +895,8 @@ void dump_keys() { if (emmc_storage.initialized) { emummc_storage_end(); } + + minerva_change_freq(FREQ_800); gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); gfx_clear_grey(0x1B); diff --git a/source/main.c b/source/main.c index 4487321..a920f70 100644 --- a/source/main.c +++ b/source/main.c @@ -339,7 +339,6 @@ void ipl_main() // Train DRAM and switch to max frequency. if (minerva_init()) //!TODO: Add Tegra210B01 support to minerva. h_cfg.errors |= ERR_LIBSYS_MTC; - minerva_change_freq(FREQ_1600); display_init(); @@ -380,6 +379,8 @@ void ipl_main() ment_top[6].data = &STATE_REBOOT_FULL; } + minerva_change_freq(FREQ_800); + while (true) tui_do_menu(&menu_top); From 168d8dea2fae334c2e335d199f34fe1862d4667f Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 5 Sep 2021 16:15:59 -0600 Subject: [PATCH 127/166] Add more verbose errors to partial key dump --- source/keys/keys.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index f3c0d7a..fdf2761 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -20,6 +20,7 @@ #include "../config.h" #include +#include "../frontend/gui.h" #include #include "../gfx/tui.h" #include "../hos/hos.h" @@ -570,6 +571,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { if (ks < ARRAY_SIZE(mariko_key_vectors)) { se_aes_crypt_block_ecb(ks, DECRYPT, &data[0], mariko_key_vectors[ks]); if (_key_exists(data)) { + EPRINTFARGS("Failed to validate keyslot %d.", ks); continue; } } @@ -587,6 +589,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { // Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot if (memcmp(&data[0], &data[SE_KEY_128_SIZE], AES_128_KEY_SIZE) == 0) { + EPRINTFARGS("Failed to overwrite keyslot %d.", ks); continue; } @@ -601,7 +604,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { free(data); if (strlen(text_buffer) == 0) { - EPRINTF("Failed to dump partial keys."); + EPRINTFARGS("Failed to dump partial keys %d-%d.", start, start + count - 1); return; } From a5fadfb592944d8e59ffd8754548920c87a17403 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 5 Sep 2021 16:21:09 -0600 Subject: [PATCH 128/166] Add screenshot option after key dump --- source/frontend/gui.c | 99 +++++++++++++++++++++++++++++++++++++++++++ source/frontend/gui.h | 17 ++++++++ source/gfx/gfx.c | 6 +-- source/keys/keys.c | 14 +++++- 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 source/frontend/gui.c create mode 100644 source/frontend/gui.h diff --git a/source/frontend/gui.c b/source/frontend/gui.c new file mode 100644 index 0000000..da5525a --- /dev/null +++ b/source/frontend/gui.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2021 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 . + */ + +#include "../gfx/gfx.h" +#include +#include +#include +#include + +#include + +int save_fb_to_bmp() +{ + // Disallow screenshots if less than 2s passed. + static u32 timer = 0; + if (get_tmr_ms() < timer) + return 1; + + const u32 file_size = 0x384000 + 0x36; + u8 *bitmap = malloc(file_size); + u32 *fb = malloc(0x384000); + u32 *fb_ptr = gfx_ctxt.fb; + + // Reconstruct FB for bottom-top, portrait bmp. + for (int y = 1279; y > -1; y--) + { + for (u32 x = 0; x < 720; x++) + fb[y * 720 + x] = *fb_ptr++; + } + + memcpy(bitmap + 0x36, fb, 0x384000); + + typedef struct _bmp_t + { + u16 magic; + u32 size; + u32 rsvd; + u32 data_off; + u32 hdr_size; + u32 width; + u32 height; + u16 planes; + u16 pxl_bits; + u32 comp; + u32 img_size; + u32 res_h; + u32 res_v; + u64 rsvd2; + } __attribute__((packed)) bmp_t; + + bmp_t *bmp = (bmp_t *)bitmap; + + bmp->magic = 0x4D42; + bmp->size = file_size; + bmp->rsvd = 0; + bmp->data_off = 0x36; + bmp->hdr_size = 40; + bmp->width = 720; + bmp->height = 1280; + bmp->planes = 1; + bmp->pxl_bits = 32; + bmp->comp = 0; + bmp->img_size = 0x384000; + bmp->res_h = 2834; + bmp->res_v = 2834; + bmp->rsvd2 = 0; + + sd_mount(); + + f_mkdir("sd:/switch"); + + char path[0x80] = "sd:/switch/lockpick_rcm.bmp"; + + // Save screenshot and log. + int res = sd_save_to_file(bitmap, file_size, path); + + // sd_unmount(); + + free(bitmap); + free(fb); + + // Set timer to 2s. + timer = get_tmr_ms() + 2000; + + return res; +} diff --git a/source/frontend/gui.h b/source/frontend/gui.h new file mode 100644 index 0000000..b6c45aa --- /dev/null +++ b/source/frontend/gui.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018-2021 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 . + */ + +int save_fb_to_bmp(); diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index db57ec1..55b41c8 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -224,7 +224,7 @@ void gfx_putc(char c) cbuf++; } 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.y += 16; @@ -233,7 +233,7 @@ void gfx_putc(char c) else if (c == '\n') { gfx_con.x = 0; - gfx_con.y +=16; + gfx_con.y += 16; if (gfx_con.y > gfx_ctxt.height - 16) gfx_con.y = 0; } @@ -259,7 +259,7 @@ void gfx_putc(char c) fb += gfx_ctxt.stride - 8; } gfx_con.x += 8; - if (gfx_con.x >= gfx_ctxt.width - 8) + if (gfx_con.x > gfx_ctxt.width - 8) { gfx_con.x = 0; gfx_con.y += 8; diff --git a/source/keys/keys.c b/source/keys/keys.c index fdf2761..f800566 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -900,8 +900,18 @@ void dump_keys() { } minerva_change_freq(FREQ_800); - gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); - btn_wait(); + gfx_printf("\n%kPress VOL+ to save a screenshot\n or another button to return to the menu.\n\n", colors[(color_idx++) % 6]); + u8 btn = btn_wait(); + if (btn == BTN_VOL_UP) { + int res = save_fb_to_bmp(); + if (!res) { + gfx_printf("%kScreenshot sd:/switch/lockpick_rcm.bmp saved.", colors[(color_idx++) % 6]); + } else { + EPRINTF("Screenshot failed."); + } + gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx++) % 6]); + btn_wait(); + } gfx_clear_grey(0x1B); } From 7e7e6fa148d845b8faf17f212d7a45f0b3e030a9 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Sep 2021 17:15:12 -0600 Subject: [PATCH 129/166] Support 13.0.0 keys --- source/hos/hos.h | 3 ++- source/keys/key_sources.inl | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/hos/hos.h b/source/hos/hos.h index ef83f5f..4ff6bd8 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -32,6 +32,7 @@ #define KB_FIRMWARE_VERSION_900 9 #define KB_FIRMWARE_VERSION_910 10 #define KB_FIRMWARE_VERSION_1210 11 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 //!TODO: Update on mkey changes. +#define KB_FIRMWARE_VERSION_1300 12 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1300 //!TODO: Update on mkey changes. #endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 3a65539..effd947 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -36,6 +36,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 {0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0 + {0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0 }; //!TODO: Update on mkey changes. @@ -52,6 +53,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ + {0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */ }; //!TODO: Update on mkey changes. @@ -68,6 +70,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr {0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */ {0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */ {0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C}, /* Master key 0A encrypted with Master key 0B. */ + {0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */ }; static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { @@ -127,6 +130,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, // 9.0.0. {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. + {0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6}, // 13.0.0. }; //!TODO: Update on mkey changes. static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. @@ -136,6 +140,7 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x82, 0x72, 0x91, 0x65, 0x40, 0x3B, 0x9D, 0x66, 0x60, 0xD0, 0x1B, 0x3D, 0x4D, 0xA5, 0x70, 0xE1}, // 9.0.0. {0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE}, // 9.1.0. {0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0. + {0x4D, 0x5A, 0xB2, 0xC9, 0xE9, 0xE4, 0x4E, 0xA4, 0xD3, 0xBF, 0x94, 0x12, 0x36, 0x30, 0xD0, 0x7F}, // 13.0.0. }; //!TODO: Update on mkey changes. static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -148,6 +153,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ + {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ }; //!TODO: Update on mkey changes. // from ES @@ -174,6 +180,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ + {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -186,6 +193,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */ {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ + {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. // from SPL From 229bc3cb44185122cd16519d78cb4b3260ab3a27 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Sep 2021 17:46:14 -0600 Subject: [PATCH 130/166] Add embedded payload version --- Makefile | 7 ++++--- bdk/utils/types.h | 8 ++++++++ loader/Makefile | 6 +++--- loader/link.ld | 1 + loader/loader.c | 6 ++++++ source/link.ld | 1 + source/main.c | 6 ++++++ 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 1fdc863..efb9df7 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ include $(DEVKITARM)/base_rules ################################################################################ IPL_LOAD_ADDR := 0x40008000 +MAGIC = 0x4B434F4C #"LOCK" include ./Versions.inc ################################################################################ @@ -37,8 +38,8 @@ FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"' ################################################################################ -CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) +CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DLP_MAGIC=$(MAGIC) +CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -DLP_RESERVED=$(LPVERSION_RSVD) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) #CUSTOMDEFINES += -DDEBUG @@ -51,7 +52,7 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) LDRDIR := $(wildcard loader) diff --git a/bdk/utils/types.h b/bdk/utils/types.h index a56b202..b9c269e 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -109,6 +109,14 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t static_assert(sizeof(boot_cfg_t) == 0x84, "Boot CFG size is wrong!"); +typedef struct __attribute__((__packed__)) _ipl_ver_meta_t +{ + u32 magic; + u32 version; + u16 rsvd0; + u16 rsvd1; +} ipl_ver_meta_t; + typedef struct __attribute__((__packed__)) _reloc_meta_t { u32 start; diff --git a/loader/Makefile b/loader/Makefile index d59ed08..06f46e4 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -7,7 +7,7 @@ include $(DEVKITARM)/base_rules ################################################################################ LDR_LOAD_ADDR := 0x40007000 -IPL_MAGIC := 0x43544349 #"ICTC" +MAGIC := 0x4B434F4C #"LOCK" include ../Versions.inc ################################################################################ @@ -26,8 +26,8 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ ################################################################################ -CUSTOMDEFINES := -DBL_MAGIC=$(IPL_MAGIC) -CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD) +CUSTOMDEFINES := -DLP_MAGIC=$(MAGIC) +CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -DLP_RESERVED=$(LPVERSION_RSVD) #TODO: Considering reinstating some of these when pointer warnings have been fixed. WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overflow diff --git a/loader/link.ld b/loader/link.ld index cf5cb17..ae0b3d1 100644 --- a/loader/link.ld +++ b/loader/link.ld @@ -6,6 +6,7 @@ SECTIONS { .text : { *(.text._start); KEEP(*(._boot_cfg)); + KEEP(*(._ipl_version)); *(.text*); } .data : { diff --git a/loader/loader.c b/loader/loader.c index 11e6018..b202efe 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -30,6 +30,12 @@ #define IPL_PATCHED_RELOC_SZ 0x94 boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; +const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { + .magic = LP_MAGIC, + .version = (LP_VER_MJ + '0') | ((LP_VER_MN + '0') << 8) | ((LP_VER_BF + '0') << 16), + .rsvd0 = 0, + .rsvd1 = 0 +}; void loader_main() { diff --git a/source/link.ld b/source/link.ld index fe49b0c..335be02 100644 --- a/source/link.ld +++ b/source/link.ld @@ -6,6 +6,7 @@ SECTIONS { .text : { *(.text._start); KEEP(*(._boot_cfg)); + KEEP(*(._ipl_version)); *(.text._irq_setup); *(.text*); } diff --git a/source/main.c b/source/main.c index a920f70..8e6e8ab 100644 --- a/source/main.c +++ b/source/main.c @@ -46,6 +46,12 @@ hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; +const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { + .magic = LP_MAGIC, + .version = (LP_VER_MJ + '0') | ((LP_VER_MN + '0') << 8) | ((LP_VER_BF + '0') << 16), + .rsvd0 = 0, + .rsvd1 = 0 +}; volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; From 0f08725e8a7765aefbca30ab38713877c803645f Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Sep 2021 18:00:03 -0600 Subject: [PATCH 131/166] Add reboot to Hekate option in main menu --- source/main.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/source/main.c b/source/main.c index 8e6e8ab..f1baf1b 100644 --- a/source/main.c +++ b/source/main.c @@ -282,6 +282,12 @@ out: btn_wait(); } +void launch_hekate() +{ + if (!f_stat("bootloader/update.bin", NULL)) + launch_payload("bootloader/update.bin", false); +} + void dump_sysnand() { h_cfg.emummc_force_disable = true; @@ -309,10 +315,11 @@ ment_t ment_top[] = { MDEF_HANDLER("Dump from EmuNAND", dump_emunand, COLOR_ORANGE), MDEF_CAPTION("---------------", COLOR_YELLOW), MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), - MDEF_CAPTION("---------------", COLOR_BLUE), - MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_VIOLET), - MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_RED), - MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_ORANGE), + MDEF_HANDLER("Reboot to Hekate", launch_hekate, COLOR_BLUE), + MDEF_CAPTION("---------------", COLOR_VIOLET), + MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_RED), + MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_ORANGE), + MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_YELLOW), MDEF_END() }; @@ -375,14 +382,22 @@ void ipl_main() // Grey out reboot to RCM option if on Mariko or patched console. if (h_cfg.t210b01 || h_cfg.rcm_patched) { - ment_top[6].type = MENT_CAPTION; - ment_top[6].color = 0xFF555555; - ment_top[6].handler = NULL; + ment_top[7].type = MENT_CAPTION; + ment_top[7].color = 0xFF555555; + ment_top[7].handler = NULL; } if (h_cfg.rcm_patched) { - ment_top[6].data = &STATE_REBOOT_FULL; + ment_top[7].data = &STATE_REBOOT_FULL; + } + + // Grey out reboot to Hekate option if no update.bin found. + if (f_stat("bootloader/update.bin", NULL)) + { + ment_top[4].type = MENT_CAPTION; + ment_top[4].color = 0xFF555555; + ment_top[4].handler = NULL; } minerva_change_freq(FREQ_800); From 4e5c9f1e85df95294a71d488d352ca49aa9499d8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 15 Sep 2021 18:01:06 -0600 Subject: [PATCH 132/166] Bump version to v1.9.5 --- Versions.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 488bd80..86de672 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,4 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 4 +LPVERSION_BUGFX := 5 +LPVERSION_RSVD := 0 From 69f8c8f33993de51dca28a2a4bf9dda0c691f0f0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 16 Sep 2021 09:20:59 -0600 Subject: [PATCH 133/166] Ensure SD mounted before reboot to hekate --- source/keys/keys.c | 2 +- source/main.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index f800566..dd6f8e4 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -896,7 +896,7 @@ void dump_keys() { h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; emu_cfg.enabled = !h_cfg.emummc_force_disable; if (emmc_storage.initialized) { - emummc_storage_end(); + sdmmc_storage_end(&emmc_storage); } minerva_change_freq(FREQ_800); diff --git a/source/main.c b/source/main.c index f1baf1b..7a1c0d4 100644 --- a/source/main.c +++ b/source/main.c @@ -284,6 +284,7 @@ out: void launch_hekate() { + sd_mount(); if (!f_stat("bootloader/update.bin", NULL)) launch_payload("bootloader/update.bin", false); } From a1f476eb0d560f4ae2c04dc5566e978c91264117 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 19 Sep 2021 14:09:56 -0600 Subject: [PATCH 134/166] Correct capitalization of hekate --- source/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/main.c b/source/main.c index 7a1c0d4..2093dd2 100644 --- a/source/main.c +++ b/source/main.c @@ -316,7 +316,7 @@ ment_t ment_top[] = { MDEF_HANDLER("Dump from EmuNAND", dump_emunand, COLOR_ORANGE), MDEF_CAPTION("---------------", COLOR_YELLOW), MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), - MDEF_HANDLER("Reboot to Hekate", launch_hekate, COLOR_BLUE), + MDEF_HANDLER("Reboot to hekate", launch_hekate, COLOR_BLUE), MDEF_CAPTION("---------------", COLOR_VIOLET), MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_RED), MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_ORANGE), @@ -393,7 +393,7 @@ void ipl_main() ment_top[7].data = &STATE_REBOOT_FULL; } - // Grey out reboot to Hekate option if no update.bin found. + // Grey out reboot to hekate option if no update.bin found. if (f_stat("bootloader/update.bin", NULL)) { ment_top[4].type = MENT_CAPTION; From 3edae524cd1c4e100ba4351063b3a986fbf255b8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 19 Sep 2021 14:26:22 -0600 Subject: [PATCH 135/166] Update to hekate bdk 5.6.1 --- bdk/mem/sdram.h | 6 +- bdk/mem/sdram_config_t210b01.inl | 98 ++-- bdk/mem/sdram_lp0.c | 774 +++++++++++++++---------------- bdk/sec/tsec.c | 11 + bdk/soc/ccplex.c | 19 +- bdk/soc/clock.c | 46 +- bdk/soc/clock.h | 34 +- bdk/storage/sdmmc_driver.c | 16 +- 8 files changed, 516 insertions(+), 488 deletions(-) diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h index 90e688d..3caac47 100644 --- a/bdk/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -87,7 +87,7 @@ enum sdram_ids_mariko LPDDR4X_IOWA_4GB_SAMSUNG_1Y_Y = 20, LPDDR4X_IOWA_8GB_SAMSUNG_1Y_Y = 21, - // LPDDR4X_AULA_4GB_SAMSUNG_1Y_A = 22, // Unused. + // LPDDR4X_AULA_8GB_SAMSUNG_1Y_A = 22, // Unused. LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. @@ -103,7 +103,7 @@ enum sdram_codes_mariko { LPDDR4X_NO_PATCH = 0, LPDDR4X_UNUSED = 0, - + // LPDDR4X_4GB_SAMSUNG_K4U6E3S4AM_MGCJ DRAM IDs: 08, 12. // LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLHR_NME DRAM IDs: 10, 14. @@ -115,7 +115,7 @@ enum sdram_codes_mariko LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 6, // DRAM IDs: 18, 23, 28. LPDDR4X_4GB_SAMSUNG_1Y_Y = 7, // DRAM IDs: 20. LPDDR4X_8GB_SAMSUNG_1Y_Y = 8, // DRAM IDs: 21. - //LPDDR4X_4GB_SAMSUNG_1Y_A = 9, // DRAM IDs: 22. Unused. + //LPDDR4X_8GB_SAMSUNG_1Y_A = 9, // DRAM IDs: 22. Unused. LPDDR4X_4GB_MICRON_1Y_A = 10, // DRAM IDs: 25, 26, 27. LPDDR4X_4GB_HYNIX_1Y_A = 11, // DRAM IDs: 03, 05, 06. }; diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl index 745399d..0d1d617 100644 --- a/bdk/mem/sdram_config_t210b01.inl +++ b/bdk/mem/sdram_config_t210b01.inl @@ -921,69 +921,41 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x00000002, 0x6E0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_Y }, // mc_video_protect_gpu_override1. /* - // Samsung LPDDR4X 4GB 10nm-class (1y-A01) Die-? for prototype (?) Aula. Unused. - { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_auto_cal_vref_sel0. - { 0x00000008, 0x24C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_tfaw. - { 0x1C041B06, 0x26C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_0. - { 0x02050307, 0x270 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_1. - { 0x03252500, 0x274 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd0_2. - { 0x081D1E00, 0x278 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_0. - { 0x090C0A0D, 0x27C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_1. - { 0x0526260B, 0x280 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd1_2. - { 0x05030402, 0x284 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_0. - { 0x1B1C0600, 0x288 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_1. - { 0x07252507, 0x28C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd2_2. - { 0x0C1D0B0A, 0x290 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_0. - { 0x0800090D, 0x294 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_1. - { 0x0926261E, 0x298 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_cmd3_2. - { 0x2A080624, 0x29C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_cmd_mapping_byte. - { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_mrw14. - { 0x80000713, 0x32C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_dyn_self_ref_control. - { 0x00140010, 0x3AC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank0_4. - { 0x0013000B, 0x3B0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank0_5. - { 0x00140010, 0x3C4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank1_4. - { 0x0013000B, 0x3C8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dq_rank1_5. - { 0x00450047, 0x3CC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. - { 0x004D004F, 0x3D0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. - { 0x00460046, 0x3D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. - { 0x00480048, 0x3D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. - { 0x000C0008, 0x3DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. - { 0x000B000C, 0x3E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank0_5. - { 0x00450047, 0x3E4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. - { 0x004D004F, 0x3E8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. - { 0x00460046, 0x3EC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. - { 0x00480048, 0x3F0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. - { 0x000C0008, 0x3F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. - { 0x000B000C, 0x3F8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ob_ddll_long_dqs_rank1_5. - { 0x00100010, 0x41C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_0. - { 0x00140014, 0x420 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_1. - { 0x00130013, 0x428 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_3. - { 0x00000010, 0x42C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_ddll_long_cmd_4. - { 0x40280100, 0x4B4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // pmc_ddr_cfg. - { 0x4F9F9FFF, 0x4B8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // pmc_io_dpd3_req. - { 0x64032157, 0x4D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte0. - { 0x51320467, 0x4DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte1. - { 0x04735621, 0x4E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte2. - { 0x47356012, 0x4E4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank0_byte3. - { 0x12045673, 0x4E8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte0. - { 0x43657210, 0x4EC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte1. - { 0x65402137, 0x4F0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte2. - { 0x57302164, 0x4F4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_swizzle_rank1_byte3. - { 0x4F9F9FFF, 0x534 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmc_scratch1. - { 0x4033CF1F, 0x53C / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmc_scratch3. - { 0x10000000, 0x590 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd3. - { 0x00030108, 0x594 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd4. - { 0x01400050, 0x598 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd5. - { 0x29081081, 0x5A0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping0. - { 0x54A59332, 0x5A4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping1. - { 0x87766B4A, 0x5A8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // emc_pmacro_brick_mapping2. - { 0x00000001, 0x670 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_emem_arb_timing_faw. - { 0xE4FACB43, 0x6D4 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_vpr_override. + TSEC, NVENC. - { 0x0600FED3, 0x6D8 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. - { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // mc_video_protect_gpu_override1. - { 0x0000009C, 0x814 / 4, LPDDR4X_4GB_SAMSUNG_1Y_A }, // swizzle_rank_byte_encode. + // Samsung LPDDR4X 8GB 10nm-class (1y-A01) Die-? for SDEV Aula? + { 0x00000001, 0x134 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_adr_cfg. 2 Ranks. + { 0x08010004, 0x2B8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw1. + { 0x08020000, 0x2BC / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw2. + { 0x080D0000, 0x2C0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw3. + { 0x08033131, 0x2C8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw6. + { 0x080B0000, 0x2CC / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw8. + { 0x0C0E5D5D, 0x2D0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw9. + { 0x080C5D5D, 0x2D4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw10. + { 0x0C0D0808, 0x2D8 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw12. + { 0x0C0D0000, 0x2DC / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw13. + { 0x08161414, 0x2E0 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw14. + { 0x08010004, 0x2E4 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_mrw_extra. + { 0x00000000, 0x340 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_dev_select. Both devices. + { 0x35353535, 0x350 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_vref_dq_0. + { 0x35353535, 0x354 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_vref_dq_1. + { 0x35353535, 0x358 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_vref_dqs_0. + { 0x35353535, 0x35C / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_vref_dqs_1. + { 0x00480048, 0x3FC / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. + { 0x00480048, 0x400 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. + { 0x00480048, 0x404 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. + { 0x00480048, 0x408 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. + { 0x00480048, 0x40C / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. + { 0x00480048, 0x410 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. + { 0x00480048, 0x414 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. + { 0x00480048, 0x418 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. + { 0x0051004F, 0x450 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_zcal_mrw_cmd. + { 0x40000001, 0x45C / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_zcal_init_dev1. + { 0x00010100, 0x594 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd4. + { 0x00400010, 0x598 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // emc_pmacro_tx_pwrd5. + { 0x00000001, 0x630 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_adr_cfg. 2 Ranks. + { 0x00002000, 0x64C / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_cfg. 8GB total density. + { 0x00000002, 0x670 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_arb_timing_faw. + { 0x00000002, 0x680 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_arb_timing_r2r. + { 0x02020001, 0x694 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_arb_da_turns. */ // Micron LPDDR4X 4GB 10nm-class (1y-01) Die-A for Unknown Iowa/Hoag/Aula. { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_auto_cal_config2. diff --git a/bdk/mem/sdram_lp0.c b/bdk/mem/sdram_lp0.c index 1c6e7e3..e0fc409 100644 --- a/bdk/mem/sdram_lp0.c +++ b/bdk/mem/sdram_lp0.c @@ -1125,408 +1125,408 @@ static void _sdram_lp0_save_params_t210(const void *params) c32(0, scratch4); s(PllMStableTime, 9:0, scratch4, 9:0); } +/* +#pragma GCC diagnostic ignored "-Wparentheses" -// #pragma GCC diagnostic ignored "-Wparentheses" +static void _sdram_lp0_save_params_t210b01(const void *params) +{ + struct sdram_params_t210b01 *sdram = (struct sdram_params_t210b01 *)params; + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; -// static void _sdram_lp0_save_params_t210b01(const void *params) -// { -// struct sdram_params_t210b01 *sdram = (struct sdram_params_t210b01 *)params; -// struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + u32 tmp = 0; -// u32 tmp = 0; + sdram->mc_generalized_carveout1_cfg0 = 0; + sdram->mc_generalized_carveout2_cfg0 = 0; + sdram->mc_generalized_carveout3_cfg0 = 0; + sdram->mc_generalized_carveout4_cfg0 = 0; + sdram->mc_generalized_carveout5_cfg0 = 0; -// sdram->mc_generalized_carveout1_cfg0 = 0; -// sdram->mc_generalized_carveout2_cfg0 = 0; -// sdram->mc_generalized_carveout3_cfg0 = 0; -// sdram->mc_generalized_carveout4_cfg0 = 0; -// sdram->mc_generalized_carveout5_cfg0 = 0; + // Patch SDRAM parameters. + u32 t0 = sdram->emc_swizzle_rank0_byte0 << 5 >> 29 > sdram->emc_swizzle_rank0_byte0 << 1 >> 29; + u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->emc_swizzle_rank1_byte0 << 5 >> 29 > sdram->emc_swizzle_rank1_byte0 << 1 >> 29) << 4); + u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->emc_swizzle_rank0_byte1 << 5 >> 29 > sdram->emc_swizzle_rank0_byte1 << 1 >> 29) << 1); + u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->emc_swizzle_rank1_byte1 << 5 >> 29 > sdram->emc_swizzle_rank1_byte1 << 1 >> 29) << 5); + u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->emc_swizzle_rank0_byte2 << 5 >> 29 > sdram->emc_swizzle_rank0_byte2 << 1 >> 29) << 2); + u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->emc_swizzle_rank1_byte2 << 5 >> 29 > sdram->emc_swizzle_rank1_byte2 << 1 >> 29) << 6); + u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->emc_swizzle_rank0_byte3 << 5 >> 29 > sdram->emc_swizzle_rank0_byte3 << 1 >> 29) << 3); + u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->emc_swizzle_rank1_byte3 << 5 >> 29 > sdram->emc_swizzle_rank1_byte3 << 1 >> 29) << 7); + sdram->swizzle_rank_byte_encode = t7; + sdram->emc_bct_spare2 = 0x40000DD8; + sdram->emc_bct_spare3 = t7; -// // Patch SDRAM parameters. -// u32 t0 = sdram->emc_swizzle_rank0_byte0 << 5 >> 29 > sdram->emc_swizzle_rank0_byte0 << 1 >> 29; -// u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->emc_swizzle_rank1_byte0 << 5 >> 29 > sdram->emc_swizzle_rank1_byte0 << 1 >> 29) << 4); -// u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->emc_swizzle_rank0_byte1 << 5 >> 29 > sdram->emc_swizzle_rank0_byte1 << 1 >> 29) << 1); -// u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->emc_swizzle_rank1_byte1 << 5 >> 29 > sdram->emc_swizzle_rank1_byte1 << 1 >> 29) << 5); -// u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->emc_swizzle_rank0_byte2 << 5 >> 29 > sdram->emc_swizzle_rank0_byte2 << 1 >> 29) << 2); -// u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->emc_swizzle_rank1_byte2 << 5 >> 29 > sdram->emc_swizzle_rank1_byte2 << 1 >> 29) << 6); -// u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->emc_swizzle_rank0_byte3 << 5 >> 29 > sdram->emc_swizzle_rank0_byte3 << 1 >> 29) << 3); -// u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->emc_swizzle_rank1_byte3 << 5 >> 29 > sdram->emc_swizzle_rank1_byte3 << 1 >> 29) << 7); -// sdram->swizzle_rank_byte_encode = t7; -// sdram->emc_bct_spare2 = 0x40000DD8; -// sdram->emc_bct_spare3 = t7; + s(emc_clock_source, 7:0, scratch6, 15:8); + s(emc_clock_source_dll, 7:0, scratch6, 23:16); + s(emc_clock_source, 31:29, scratch6, 26:24); + s(emc_clock_source_dll, 31:29, scratch6, 29:27); + s(emc_clock_source_dll, 11:10, scratch6, 31:30); + pmc->scratch7 = (sdram->emc_rc << 24) | ((sdram->emc_zqcal_lpddr4_warm_boot << 27 >> 31 << 23) | ((sdram->emc_zqcal_lpddr4_warm_boot << 30 >> 31 << 22) | ((sdram->emc_zqcal_lpddr4_warm_boot << 21) & 0x3FFFFF | ((sdram->clk_rst_pllm_misc20_override << 20) & 0x1FFFFF | ((sdram->clk_rst_pllm_misc20_override << 28 >> 31 << 19) | ((sdram->clk_rst_pllm_misc20_override << 27 >> 31 << 18) | ((sdram->clk_rst_pllm_misc20_override << 26 >> 31 << 17) | ((sdram->clk_rst_pllm_misc20_override << 21 >> 31 << 16) | ((sdram->clk_rst_pllm_misc20_override << 20 >> 31 << 15) | ((sdram->clk_rst_pllm_misc20_override << 19 >> 31 << 14) | ((sdram->clk_rst_pllm_misc20_override << 18 >> 31 << 13) | ((sdram->emc_clock_source << 15 >> 31 << 12) | ((sdram->emc_clock_source << 11 >> 31 << 11) | ((sdram->emc_clock_source << 12 >> 31 << 10) | ((sdram->emc_clock_source << 6 >> 31 << 9) | ((sdram->emc_clock_source << 16 >> 31 << 8) | ((32 * sdram->emc_clock_source >> 31 << 7) | ((16 * sdram->emc_clock_source >> 31 << 6) | (16 * (sdram->emc_zqcal_lpddr4_warm_boot >> 30) | (4 * (sdram->clk_rst_pllm_misc20_override << 29 >> 30) | ((sdram->clk_rst_pllm_misc20_override << 22 >> 30) | 4 * (pmc->scratch7 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFFFFFF; + pmc->scratch8 = (sdram->emc_pmacro_bg_bias_ctrl0 << 18 >> 30 << 30) | ((4 * pmc->scratch8) >> 2); + pmc->scratch14 = ((u8)(sdram->emc_cfg_pipe_clk) << 31) | (2 * (((u8)(sdram->emc_fdpd_ctrl_cmd_no_ramp) << 30) | pmc->scratch14 & 0xBFFFFFFF) >> 1); + s(emc_qrst, 6:0, scratch15, 26:20); + s(emc_qrst, 20:16, scratch15, 31:27); + s(emc_pmacro_cmd_tx_drive, 5:0, scratch16, 25:20); + s(emc_pmacro_cmd_tx_drive, 13:8, scratch16, 31:26); + pmc->scratch17 = (16 * sdram->emc_fbio_cfg8 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg8 >> 31 << 30) | ((sdram->emc_fbio_cfg8 << 6 >> 31 << 29) | ((sdram->emc_fbio_cfg8 << 7 >> 31 << 28) | ((sdram->emc_fbio_cfg8 << 8 >> 31 << 27) | ((sdram->emc_fbio_cfg8 << 9 >> 31 << 26) | ((sdram->emc_fbio_cfg8 << 10 >> 31 << 25) | ((sdram->emc_fbio_cfg8 << 11 >> 31 << 24) | ((sdram->emc_fbio_cfg8 << 12 >> 31 << 23) | ((sdram->emc_fbio_cfg8 << 13 >> 31 << 22) | ((sdram->emc_fbio_cfg8 << 14 >> 31 << 21) | ((sdram->emc_fbio_cfg8 << 15 >> 31 << 20) | pmc->scratch17 & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch18 = ((u16)(sdram->emc_txsr_dll) << 20) | pmc->scratch18 & 0xFFFFF; + pmc->scratch19 = (sdram->emc_txdsrvttgen << 20) | pmc->scratch19 & 0xFFFFF; + s32(emc_cfg_rsv, scratch22); + s32(emc_auto_cal_config, scratch23); + s32(emc_auto_cal_vref_sel0, scratch24); + s32(emc_pmacro_brick_ctrl_rfu1, scratch25); + s32(emc_pmacro_brick_ctrl_rfu2, scratch26); + s32(emc_pmc_scratch1, scratch27); + s32(emc_pmc_scratch2, scratch28); + s32(emc_pmc_scratch3, scratch29); + pmc->scratch30 = (sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl0 & 3 | 4 * (pmc->scratch30 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch31 = (sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl1 & 3 | 4 * (pmc->scratch31 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch32 = (sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl2 & 3 | 4 * (pmc->scratch32 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch33 = (sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl3 & 3 | 4 * (pmc->scratch33 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch40 = (sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl4 & 3 | 4 * (pmc->scratch40 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch42 = (sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl5 & 3 | 4 * (pmc->scratch42 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch44 = (sdram->mc_emem_arb_da_turns >> 24 << 24) | ((sdram->mc_emem_arb_da_turns >> 16 << 16) | ((sdram->mc_emem_arb_da_turns << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_turns & 0xFF | (pmc->scratch44 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; + pmc->scratch64 = ((u16)(sdram->mc_emem_arb_misc2) << 31) | (2 * ((sdram->emc_fbio_spare << 30) | ((sdram->emc_fbio_spare << 24 >> 26 << 24) | ((sdram->emc_fbio_spare << 16 >> 24 << 16) | ((sdram->emc_fbio_spare << 8 >> 24 << 8) | ((sdram->emc_fbio_spare >> 24) | (pmc->scratch64 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch65 = ((u16)(sdram->mc_da_cfg0) << 31 >> 1) | ((2 * sdram->mc_emem_arb_misc0 >> 29 << 27) | ((16 * sdram->mc_emem_arb_misc0 >> 31 << 26) | ((32 * sdram->mc_emem_arb_misc0 >> 26 << 20) | ((sdram->mc_emem_arb_misc0 << 11 >> 27 << 15) | ((sdram->mc_emem_arb_misc0 << 17 >> 25 << 8) | ((u8)sdram->mc_emem_arb_misc0 | (pmc->scratch65 >> 8 << 8)) & 0xFFFF80FF) & 0xFFF07FFF) & 0xFC0FFFFF) & 0xFBFFFFFF) & 0xC7FFFFFF) & 0xBFFFFFFF; + pmc->scratch66 = (sdram->emc_fdpd_ctrl_cmd >> 30 << 27) | ((4 * sdram->emc_fdpd_ctrl_cmd >> 31 << 26) | ((8 * sdram->emc_fdpd_ctrl_cmd >> 27 << 21) | ((sdram->emc_fdpd_ctrl_cmd << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_cmd << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_cmd << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_cmd | (pmc->scratch66 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xFBFFFFFF) & 0xE7FFFFFF; + pmc->scratch67 = ((u8)(sdram->emc_burst_refresh_num) << 28) | ((16 * sdram->emc_auto_cal_config2 >> 30 << 26) | ((sdram->emc_auto_cal_config2 << 6 >> 30 << 24) | ((sdram->emc_auto_cal_config2 << 8 >> 30 << 22) | ((sdram->emc_auto_cal_config2 << 10 >> 30 << 20) | ((sdram->emc_auto_cal_config2 << 12 >> 30 << 18) | ((sdram->emc_auto_cal_config2 << 14 >> 30 << 16) | ((sdram->emc_auto_cal_config2 << 16 >> 30 << 14) | ((sdram->emc_auto_cal_config2 << 18 >> 30 << 12) | ((sdram->emc_auto_cal_config2 << 20 >> 30 << 10) | ((sdram->emc_auto_cal_config2 << 22 >> 30 << 8) | ((sdram->emc_auto_cal_config2 << 24 >> 30 << 6) | (16 * (sdram->emc_auto_cal_config2 << 26 >> 30) | (4 * (sdram->emc_auto_cal_config2 << 28 >> 30) | (sdram->emc_auto_cal_config2 & 3 | 4 * (pmc->scratch67 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; + pmc->scratch68 = ((u8)(sdram->emc_tppd) << 28) | ((sdram->emc_cfg_dig_dll >> 31 << 27) | ((2 * sdram->emc_cfg_dig_dll >> 31 << 26) | ((16 * sdram->emc_cfg_dig_dll >> 31 << 25) | ((sdram->emc_cfg_dig_dll << 6 >> 22 << 15) | ((sdram->emc_cfg_dig_dll << 16 >> 31 << 14) | ((sdram->emc_cfg_dig_dll << 17 >> 31 << 13) | ((sdram->emc_cfg_dig_dll << 18 >> 30 << 11) | ((sdram->emc_cfg_dig_dll << 21 >> 29 << 8) | ((sdram->emc_cfg_dig_dll << 24 >> 30 << 6) | (32 * (sdram->emc_cfg_dig_dll << 26 >> 31) | (16 * (sdram->emc_cfg_dig_dll << 27 >> 31) | (8 * (sdram->emc_cfg_dig_dll << 28 >> 31) | (4 * (sdram->emc_cfg_dig_dll << 29 >> 31) | (2 * (sdram->emc_cfg_dig_dll << 30 >> 31) | (sdram->emc_cfg_dig_dll & 1 | 2 * (pmc->scratch68 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFF3F) & 0xFFFFF8FF) & 0xFFFFE7FF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFE007FFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; + pmc->scratch69 = (sdram->emc_r2r << 28) | ((sdram->emc_fdpd_ctrl_dq >> 30 << 26) | ((8 * sdram->emc_fdpd_ctrl_dq >> 27 << 21) | ((sdram->emc_fdpd_ctrl_dq << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_dq << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_dq << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_dq | (pmc->scratch69 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; + pmc->scratch70 = (sdram->emc_w2w << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_0 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ib_vref_dq_0 & 0x7F | (pmc->scratch70 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->scratch71 = (sdram->emc_pmacro_vttgen_ctrl0 << 12 >> 28 << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_1 << 17 >> 25 << 7) | ((pmc->scratch71 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dq_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->scratch72 = (((sdram->emc_pmacro_ib_vref_dqs_0 << 17 >> 25 << 7) | ((pmc->scratch72 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_0 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF | (sdram->emc_pmacro_ib_vref_dqs_0 << 9 >> 25 << 14)) & 0xF01FFFFF | (2 * sdram->emc_pmacro_ib_vref_dqs_0 >> 25 << 21); + pmc->scratch73 = (2 * sdram->emc_pmacro_ib_vref_dqs_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 17 >> 25 << 7) | ((pmc->scratch73 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch74 = (2 * sdram->emc_pmacro_ddll_short_cmd_0 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_0 & 0x7F | (pmc->scratch74 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch75 = (2 * sdram->emc_pmacro_ddll_short_cmd_1 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_1 & 0x7F | (pmc->scratch75 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch76 = (sdram->emc_rp << 26) | ((4 * sdram->emc_dll_cfg0 >> 31 << 25) | ((8 * sdram->emc_dll_cfg0 >> 31 << 24) | ((16 * sdram->emc_dll_cfg0 >> 28 << 20) | ((sdram->emc_dll_cfg0 << 8 >> 28 << 16) | ((sdram->emc_dll_cfg0 << 12 >> 28 << 12) | ((sdram->emc_dll_cfg0 << 16 >> 28 << 8) | ((sdram->emc_dll_cfg0 << 20 >> 24) | (pmc->scratch76 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = (sdram->emc_pmacro_tx_pwrd0 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd0 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd0 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd0 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd0 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd0 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd0 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd0 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd0 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd0 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd0 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd0 & 1 | 2 * (pmc->scratch77 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF; + pmc->scratch77 = (sdram->emc_r2w << 26) | ((4 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd0 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd0 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd0 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd0 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd0 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd0 << 11 >> 31 << 17) | tmp & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd1 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd1 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd1 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd1 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd1 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd1 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd1 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd1 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd1 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd1 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd1 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd1 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd1 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd1 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd1 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd1 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd1 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd1 & 1 | 2 * (pmc->scratch78 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch78 = (sdram->emc_w2r << 26) | ((4 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd2 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd2 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd2 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd2 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd2 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd2 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd2 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd2 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd2 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd2 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd2 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd2 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd2 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd2 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd2 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd2 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd2 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd2 & 1 | 2 * (pmc->scratch79 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch79 = (sdram->emc_r2p << 26) | ((4 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = (sdram->emc_pmacro_tx_pwrd3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd3 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd3 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd3 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd3 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd3 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd3 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd3 & 1 | 2 * (pmc->scratch80 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF; + pmc->scratch80 = ((u8)(sdram->emc_ccdmw) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd3 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd3 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd3 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd3 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd3 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd3 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd3 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd3 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd3 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd3 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd3 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd3 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd3 << 22 >> 31 << 9) | tmp & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd4 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd4 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd4 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd4 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd4 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd4 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd4 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd4 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd4 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd4 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd4 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd4 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd4 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd4 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd4 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd4 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd4 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd4 & 1 | 2 * (pmc->scratch81 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch81 = ((u8)(sdram->emc_rd_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd5 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd5 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd5 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd5 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd5 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd5 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd5 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd5 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd5 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd5 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd5 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd5 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd5 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd5 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd5 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd5 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd5 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd5 & 1 | 2 * (pmc->scratch82 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch82 = ((u16)(sdram->emc_wr_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 25) | tmp) & 0x3FFFFFF; + pmc->scratch83 = ((u8)(sdram->emc_config_sample_delay) << 25) | ((sdram->emc_auto_cal_channel >> 31 << 24) | ((2 * sdram->emc_auto_cal_channel >> 31 << 23) | ((4 * sdram->emc_auto_cal_channel >> 31 << 22) | ((16 * sdram->emc_auto_cal_channel >> 25 << 15) | ((sdram->emc_auto_cal_channel << 11 >> 27 << 10) | ((sdram->emc_auto_cal_channel << 20 >> 28 << 6) | (sdram->emc_auto_cal_channel & 0x3F | (pmc->scratch83 >> 6 << 6)) & 0xFFFFFC3F) & 0xFFFF83FF) & 0xFFC07FFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0x1FFFFFF; + pmc->scratch84 = (sdram->emc_sel_dpd_ctrl << 13 >> 29 << 29) | ((sdram->emc_sel_dpd_ctrl << 23 >> 31 << 28) | ((sdram->emc_sel_dpd_ctrl << 26 >> 31 << 27) | ((sdram->emc_sel_dpd_ctrl << 27 >> 31 << 26) | ((sdram->emc_sel_dpd_ctrl << 28 >> 31 << 25) | ((sdram->emc_sel_dpd_ctrl << 29 >> 31 << 24) | ((4 * sdram->emc_pmacro_rx_term >> 26 << 18) | ((sdram->emc_pmacro_rx_term << 10 >> 26 << 12) | ((sdram->emc_pmacro_rx_term << 18 >> 26 << 6) | (sdram->emc_pmacro_rx_term & 0x3F | (pmc->scratch84 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch85 = (4 * sdram->emc_obdly >> 30 << 30) | (4 * ((sdram->emc_obdly << 24) | ((4 * sdram->emc_pmacro_dq_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_dq_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_dq_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_dq_tx_drive & 0x3F | (pmc->scratch85 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); + pmc->scratch86 = (sdram->emc_pmacro_vttgen_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_vttgen_ctrl1 << 16 >> 26 << 24) | ((4 * sdram->emc_pmacro_ca_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_ca_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_ca_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_ca_tx_drive & 0x3F | (pmc->scratch86 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); + pmc->scratch87 = (sdram->emc_pmacro_vttgen_ctrl2 >> 16 << 24) | ((16 * sdram->emc_pmacro_zcrtl >> 30 << 22) | ((sdram->emc_pmacro_zcrtl << 6 >> 30 << 20) | ((sdram->emc_pmacro_zcrtl << 8 >> 30 << 18) | ((sdram->emc_pmacro_zcrtl << 10 >> 30 << 16) | ((sdram->emc_pmacro_zcrtl << 12 >> 30 << 14) | ((sdram->emc_pmacro_zcrtl << 14 >> 30 << 12) | ((sdram->emc_pmacro_zcrtl << 16 >> 30 << 10) | ((sdram->emc_pmacro_zcrtl << 18 >> 30 << 8) | ((sdram->emc_pmacro_zcrtl << 20 >> 30 << 6) | (16 * (sdram->emc_pmacro_zcrtl << 22 >> 30) | (4 * (sdram->emc_pmacro_zcrtl << 24 >> 30) | ((sdram->emc_pmacro_zcrtl << 26 >> 30) | 4 * (pmc->scratch87 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFFFFFF; + pmc->scratch88 = (sdram->mc_emem_arb_timing_rc << 24) | ((sdram->emc_zcal_interval << 14) | ((sdram->emc_zcal_interval << 8 >> 18) | (pmc->scratch88 >> 14 << 14)) & 0xFF003FFF) & 0xFFFFFF; + pmc->scratch89 = ((u16)(sdram->mc_emem_arb_rsv) << 24) | ((sdram->emc_data_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft0 << 26 >> 29) | (sdram->emc_data_brlshft0 & 7 | 8 * (pmc->scratch89 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0xFFFFFF; + pmc->scratch90 = (sdram->emc_data_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft1 << 26 >> 29) | (sdram->emc_data_brlshft1 & 7 | 8 * (pmc->scratch90 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch91 = (sdram->emc_dqs_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft0 << 26 >> 29) | (sdram->emc_dqs_brlshft0 & 7 | 8 * (pmc->scratch91 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch92 = (sdram->emc_dqs_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft1 << 26 >> 29) | (sdram->emc_dqs_brlshft1 & 7 | 8 * (pmc->scratch92 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch93 = (2 * sdram->emc_swizzle_rank0_byte0 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte0 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte0 & 7 | 8 * (pmc->scratch93 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch94 = ((u8)(sdram->emc_cfg) << 27 >> 31 << 31) | (2 * ((sdram->emc_ras << 24) | ((2 * sdram->emc_swizzle_rank0_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte1 & 7 | 8 * (pmc->scratch94 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch95 = ((u8)(sdram->emc_cfg) << 26 >> 31 << 31) | (2 * ((sdram->emc_w2p << 24) | ((2 * sdram->emc_swizzle_rank0_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte2 & 7 | 8 * (pmc->scratch95 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch96 = ((u8)(sdram->emc_cfg) << 25 >> 31 << 31) | (2 * ((sdram->emc_qsafe << 24) | ((2 * sdram->emc_swizzle_rank0_byte3 >> 29 << 21) | (((sdram->emc_swizzle_rank0_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte3 & 7 | 8 * (pmc->scratch96 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank0_byte3 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch97 = ((u8)(sdram->emc_cfg) << 24 >> 31 << 31) | (2 * ((sdram->emc_rdv << 24) | ((2 * sdram->emc_swizzle_rank1_byte0 >> 29 << 21) | (((sdram->emc_swizzle_rank1_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte0 & 7 | 8 * (pmc->scratch97 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank1_byte0 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch98 = ((u16)(sdram->emc_cfg) << 23 >> 31 << 31) | (2 * (((u16)(sdram->emc_rw2pden) << 24) | ((2 * sdram->emc_swizzle_rank1_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte1 & 7 | 8 * (pmc->scratch98 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch99 = ((u16)(sdram->emc_cfg) << 22 >> 31 << 31) | (2 * ((sdram->emc_tfaw << 24) | ((2 * sdram->emc_swizzle_rank1_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte2 & 7 | 8 * (pmc->scratch99 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch100 = (sdram->emc_cfg << 13 >> 31 << 31) | (2 * ((sdram->emc_tclkstable << 24) | ((2 * sdram->emc_swizzle_rank1_byte3 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte3 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte3 & 7 | 8 * (pmc->scratch100 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + tmp = 2 * (((u8)(sdram->emc_trtm) << 24) | ((16 * sdram->emc_cfg_pipe2 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe2 >> 31 << 22) | ((sdram->emc_cfg_pipe2 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe2 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe2 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe2 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe2 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe2 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe2 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe2 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe2 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe2 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe2 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe2 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe2 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe2 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe2 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe2 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe2 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe2 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe2 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe2 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe2 << 30 >> 31) | (sdram->emc_cfg_pipe2 & 1 | 2 * (pmc->scratch101 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch101 = (sdram->emc_cfg << 10 >> 31 << 31) | tmp; + tmp = (2 * (pmc->scratch102 >> 1) | sdram->emc_cfg_pipe1 & 1) & 0xFFFFFFFD; + pmc->scratch102 = (sdram->emc_cfg << 9 >> 31 << 31) | (2 * (((u8)(sdram->emc_twtm) << 24) | ((16 * sdram->emc_cfg_pipe1 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe1 >> 31 << 22) | ((sdram->emc_cfg_pipe1 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe1 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe1 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe1 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe1 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe1 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe1 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe1 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe1 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe1 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe1 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe1 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe1 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe1 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe1 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe1 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe1 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe1 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe1 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe1 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe1 << 30 >> 31) | tmp) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + tmp = 2 * (((u8)(sdram->emc_tratm) << 24) | ((sdram->emc_pmacro_ddll_pwrd0 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd0 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd0 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd0 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd0 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd0 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd0 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd0 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd0 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd0 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd0 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd0 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd0 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd0 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd0 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd0 << 30 >> 31) | 2 * (pmc->scratch103 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch103 = (sdram->emc_cfg << 8 >> 31 << 31) | tmp; + tmp = 2 * (((u8)(sdram->emc_twatm) << 24) | ((sdram->emc_pmacro_ddll_pwrd1 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd1 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd1 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd1 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd1 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd1 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd1 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd1 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd1 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd1 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd1 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd1 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd1 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd1 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd1 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd1 << 30 >> 31) | 2 * (pmc->scratch104 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch104 = (sdram->emc_cfg << 7 >> 31 << 31) | tmp; + tmp = (sdram->emc_pmacro_ddll_pwrd2 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd2 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd2 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd2 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd2 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd2 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd2 << 30 >> 31) | 2 * (pmc->scratch105 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF; + pmc->scratch105 = (sdram->emc_cfg << 6 >> 31 << 31) | (2 * (((u8)(sdram->emc_tr2ref) << 24) | ((sdram->emc_pmacro_ddll_pwrd2 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd2 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd2 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd2 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd2 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd2 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd2 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd2 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd2 << 21 >> 31 << 7) | tmp & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch106 = (32 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_pdex2mrr) << 24) | ((8 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 23) | ((16 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 21) | ((sdram->emc_pmacro_ddll_periodic_offset << 6 >> 31 << 20) | ((sdram->emc_pmacro_ddll_periodic_offset << 7 >> 31 << 19) | ((sdram->emc_pmacro_ddll_periodic_offset << 8 >> 31 << 18) | ((sdram->emc_pmacro_ddll_periodic_offset << 9 >> 31 << 17) | ((sdram->emc_pmacro_ddll_periodic_offset << 10 >> 31 << 16) | ((sdram->emc_pmacro_ddll_periodic_offset << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_periodic_offset << 15 >> 31 << 14) | ((sdram->emc_pmacro_ddll_periodic_offset << 16 >> 31 << 13) | ((sdram->emc_pmacro_ddll_periodic_offset << 17 >> 31 << 12) | ((sdram->emc_pmacro_ddll_periodic_offset << 18 >> 31 << 11) | ((sdram->emc_pmacro_ddll_periodic_offset << 19 >> 31 << 10) | ((sdram->emc_pmacro_ddll_periodic_offset << 20 >> 31 << 9) | ((sdram->emc_pmacro_ddll_periodic_offset << 21 >> 31 << 8) | ((sdram->emc_pmacro_ddll_periodic_offset << 22 >> 31 << 7) | ((sdram->emc_pmacro_ddll_periodic_offset << 23 >> 31 << 6) | (sdram->emc_pmacro_ddll_periodic_offset & 0x3F | (pmc->scratch106 >> 6 << 6)) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch107 = (8 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_clken_override << 15 >> 31 << 30) | ((sdram->emc_clken_override << 23 >> 31 << 29) | ((sdram->emc_clken_override << 24 >> 31 << 28) | ((sdram->emc_clken_override << 25 >> 31 << 27) | ((sdram->emc_clken_override << 28 >> 31 << 26) | ((sdram->emc_clken_override << 29 >> 31 << 25) | ((sdram->emc_clken_override << 30 >> 31 << 24) | ((sdram->mc_emem_arb_da_covers << 8 >> 24 << 16) | ((sdram->mc_emem_arb_da_covers << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_covers & 0xFF | (pmc->scratch107 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch108 = (sdram->emc_rfc_pb << 23) | ((sdram->emc_xm2_comp_pad_ctrl >> 24 << 15) | ((sdram->emc_xm2_comp_pad_ctrl << 12 >> 24 << 7) | ((sdram->emc_xm2_comp_pad_ctrl << 20 >> 31 << 6) | (32 * (sdram->emc_xm2_comp_pad_ctrl << 22 >> 31) | (4 * (sdram->emc_xm2_comp_pad_ctrl << 25 >> 29) | (sdram->emc_xm2_comp_pad_ctrl & 3 | 4 * (pmc->scratch108 >> 2)) & 0xFFFFFFE3) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFF807F) & 0xFF807FFF) & 0x7FFFFF; + pmc->scratch109 = (sdram->emc_cfg_update >> 31 << 31) | (2 * ((2 * sdram->emc_cfg_update >> 31 << 30) | ((4 * sdram->emc_cfg_update >> 31 << 29) | ((8 * sdram->emc_cfg_update >> 31 << 28) | ((sdram->emc_cfg_update << 21 >> 30 << 26) | ((sdram->emc_cfg_update << 23 >> 31 << 25) | ((sdram->emc_cfg_update << 29 >> 30 << 23) | ((sdram->emc_cfg_update << 22) & 0x7FFFFF | ((sdram->emc_auto_cal_config3 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config3 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config3 << 17 >> 25 << 7) | ((pmc->scratch109 >> 7 << 7) | sdram->emc_auto_cal_config3 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFE7FFFFF) & 0xFDFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch110 = (sdram->emc_rfc << 22) | ((sdram->emc_auto_cal_config4 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config4 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config4 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config4 & 0x7F | (pmc->scratch110 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; + pmc->scratch111 = ((u16)(sdram->emc_txsr) << 22) | ((sdram->emc_auto_cal_config5 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config5 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config5 << 17 >> 25 << 7) | ((pmc->scratch111 >> 7 << 7) | sdram->emc_auto_cal_config5 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; + pmc->scratch112 = (16 * sdram->emc_mc2emc_q >> 28 << 28) | ((sdram->emc_mc2emc_q << 21 >> 29 << 25) | ((sdram->emc_mc2emc_q << 22) & 0x1FFFFFF | ((sdram->emc_auto_cal_config6 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config6 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config6 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config6 & 0x7F | (pmc->scratch112 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xFFFFFFF; + pmc->scratch113 = (sdram->mc_emem_arb_ring1_throttle << 11 >> 27 << 27) | ((sdram->mc_emem_arb_ring1_throttle << 22) | ((sdram->emc_auto_cal_config7 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config7 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config7 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config7 & 0x7F | (pmc->scratch113 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xF83FFFFF) & 0x7FFFFFF; + pmc->scratch114 = (sdram->emc_auto_cal_config8 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config8 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config8 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config8 & 0x7F | (pmc->scratch114 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF; + pmc->scratch115 = (4 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_ar2pden) << 22) | ((sdram->emc_fbio_cfg7 << 10 >> 30 << 20) | ((sdram->emc_fbio_cfg7 << 12 >> 31 << 19) | ((sdram->emc_fbio_cfg7 << 13 >> 31 << 18) | ((sdram->emc_fbio_cfg7 << 14 >> 31 << 17) | ((sdram->emc_fbio_cfg7 << 15 >> 31 << 16) | ((sdram->emc_fbio_cfg7 << 16 >> 31 << 15) | ((sdram->emc_fbio_cfg7 << 17 >> 31 << 14) | ((sdram->emc_fbio_cfg7 << 18 >> 31 << 13) | ((sdram->emc_fbio_cfg7 << 19 >> 31 << 12) | ((sdram->emc_fbio_cfg7 << 20 >> 31 << 11) | ((sdram->emc_fbio_cfg7 << 21 >> 31 << 10) | ((sdram->emc_fbio_cfg7 << 22 >> 31 << 9) | ((sdram->emc_fbio_cfg7 << 23 >> 31 << 8) | ((sdram->emc_fbio_cfg7 << 24 >> 31 << 7) | ((sdram->emc_fbio_cfg7 << 25 >> 31 << 6) | (32 * (sdram->emc_fbio_cfg7 << 26 >> 31) | (16 * (sdram->emc_fbio_cfg7 << 27 >> 31) | (8 * (sdram->emc_fbio_cfg7 << 28 >> 31) | (4 * (sdram->emc_fbio_cfg7 << 29 >> 31) | (2 * (sdram->emc_fbio_cfg7 << 30 >> 31) | (sdram->emc_fbio_cfg7 & 1 | 2 * (pmc->scratch115 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFCFFFFF) & 0x803FFFFF) >> 1); + pmc->scratch123 = (2 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_rfc_slr << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_0 & 0x7FF | (pmc->scratch123 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); + pmc->scratch124 = (sdram->emc_cfg >> 31 << 31) | (2 * ((4 * sdram->emc_ibdly >> 30 << 29) | ((sdram->emc_ibdly << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_1 & 0x7FF | (pmc->scratch124 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch125 = (sdram->emc_fbio_cfg5 << 27 >> 31 << 31) | (2 * (((u16)(sdram->mc_emem_arb_timing_rfcpb) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_2 & 0x7FF | (pmc->scratch125 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); + pmc->scratch126 = (sdram->emc_fbio_cfg5 << 16 >> 29 << 29) | ((sdram->emc_auto_cal_config9 << 25 >> 31 << 28) | ((sdram->emc_auto_cal_config9 << 26 >> 31 << 27) | ((sdram->emc_auto_cal_config9 << 27 >> 31 << 26) | ((sdram->emc_auto_cal_config9 << 28 >> 31 << 25) | ((sdram->emc_auto_cal_config9 << 29 >> 31 << 24) | ((sdram->emc_auto_cal_config9 << 30 >> 31 << 23) | ((sdram->emc_auto_cal_config9 << 22) & 0x7FFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_3 & 0x7FF | (pmc->scratch126 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch127 = ((u8)(sdram->emc_cfg2) << 26 >> 29 << 29) | ((sdram->emc_rdv_mask << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_4 & 0x7FF | (pmc->scratch127 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch128 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 27 >> 29 << 29) | (((u8)(sdram->emc_rdv_early_mask) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_5 & 0x7FF | (pmc->scratch128 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch129 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_rdv_early << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_0 & 0x7FF | (pmc->scratch129 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch130 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 17 >> 29 << 29) | ((4 * sdram->emc_quse_width >> 31 << 28) | ((8 * sdram->emc_quse_width >> 31 << 27) | ((sdram->emc_quse_width << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_1 & 0x7FF | (pmc->scratch130 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch131 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 12 >> 29 << 29) | (((u16)(sdram->emc_pmacro_ddll_short_cmd_2) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_2 & 0x7FF | (pmc->scratch131 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch132 = (sdram->emc_pmacro_data_pad_tx_ctrl << 27 >> 29 << 29) | ((sdram->emc_pmacro_cmd_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_cmd_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_3 & 0x7FF | (pmc->scratch132 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch133 = (sdram->emc_pmacro_data_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_pmacro_data_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_data_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_data_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_data_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_4 & 0x7FF | (pmc->scratch133 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch134 = (sdram->emc_pmacro_data_pad_tx_ctrl << 17 >> 29 << 29) | ((sdram->mc_emem_arb_timing_rp << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_5 & 0x7FF | (pmc->scratch134 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch135 = (sdram->emc_pmacro_data_pad_tx_ctrl << 12 >> 29 << 29) | ((sdram->mc_emem_arb_timing_ras << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 & 0x7FF | (pmc->scratch135 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch136 = (sdram->emc_fbio_cfg5 << 23 >> 31 << 31) | (2 * ((sdram->emc_cfg << 14 >> 30 << 29) | ((sdram->mc_emem_arb_timing_faw << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 & 0x7FF | (pmc->scratch136 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch137 = (sdram->emc_fbio_cfg5 << 21 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 29) | ((sdram->mc_emem_arb_timing_rap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 & 0x7FF | (pmc->scratch137 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch138 = (sdram->emc_fbio_cfg5 << 19 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 28 >> 30 << 29) | ((sdram->mc_emem_arb_timing_wap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 & 0x7FF | (pmc->scratch138 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch139 = (sdram->emc_fbio_cfg5 << 7 >> 31 << 31) | (2 * ((16 * sdram->emc_cfg2 >> 30 << 29) | (((u8)(sdram->mc_emem_arb_timing_r2w) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 & 0x7FF | (pmc->scratch139 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch140 = (16 * sdram->emc_fbio_cfg5 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg5 >> 31 << 30) | ((sdram->emc_fbio_cfg5 << 6 >> 31 << 29) | (((u8)(sdram->mc_emem_arb_timing_w2r) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 & 0x7FF | (pmc->scratch140 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch141 = (sdram->emc_fbio_cfg5 << 8 >> 28 << 28) | (((u16)(sdram->emc_wdv) << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 & 0x7FF | (pmc->scratch141 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xFFFFFFF; + pmc->scratch142 = ((u8)(sdram->emc_cfg2) << 31) | (2 * ((sdram->emc_fbio_cfg5 >> 31 << 30) | ((2 * sdram->emc_fbio_cfg5 >> 31 << 29) | ((8 * sdram->emc_fbio_cfg5 >> 31 << 28) | ((sdram->emc_quse << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 & 0x7FF | (pmc->scratch142 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch143 = (((u16)(sdram->emc_cfg2) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg2) << 24) >> 31 << 30) | ((((u16)(sdram->emc_cfg2) << 29) >> 31 << 29) | ((((u16)(sdram->emc_cfg2) << 30) >> 31 << 28) | (((u8)(sdram->emc_pdex2wr) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 & 0x7FF | (pmc->scratch143 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch144 = (sdram->emc_cfg2 << 15 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 16 >> 31 << 30) | ((sdram->emc_cfg2 << 17 >> 31 << 29) | ((sdram->emc_cfg2 << 20 >> 31 << 28) | (((u8)(sdram->emc_pdex2rd) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 & 0x7FF | (pmc->scratch144 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch145 = (sdram->emc_cfg2 << 7 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 8 >> 31 << 30) | ((sdram->emc_cfg2 << 9 >> 31 << 29) | ((sdram->emc_cfg2 << 11 >> 31 << 28) | (((u16)(sdram->emc_pdex2che) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 & 0x7FF | (pmc->scratch145 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch146 = (2 * sdram->emc_cfg2 >> 31 << 31) | (2 * ((4 * sdram->emc_cfg2 >> 31 << 30) | (((sdram->emc_cfg2 << 6 >> 31 << 28) | (((u8)(sdram->emc_pchg2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 & 0x7FF | (pmc->scratch146 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (8 * sdram->emc_cfg2 >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch147 = (((u8)(sdram->emc_cfg_pipe) << 29) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 30) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 31) >> 2) | ((sdram->emc_cfg2 >> 31 << 28) | (((u16)(sdram->emc_act2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch147 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch148 = (((u8)(sdram->emc_cfg_pipe) << 25) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 26) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 27) >> 31 << 29) | ((((u8)(sdram->emc_cfg_pipe) << 28) >> 31 << 28) | (((u16)(sdram->emc_cke2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch148 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch149 = (((u16)(sdram->emc_cfg_pipe) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg_pipe) << 22) >> 31 << 30) | ((((u16)(sdram->emc_cfg_pipe) << 23) >> 31 << 29) | ((((u16)(sdram->emc_cfg_pipe) << 24) >> 31 << 28) | ((sdram->emc_tcke << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch149 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch150 = (sdram->emc_cfg_pipe << 13 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 14 >> 31 << 30) | (((sdram->emc_cfg_pipe << 20 >> 31 << 28) | ((sdram->emc_trpab << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch150 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (sdram->emc_cfg_pipe << 15 >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch151 = (sdram->emc_cfg_pipe << 9 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 10 >> 31 << 30) | ((sdram->emc_cfg_pipe << 11 >> 31 << 29) | ((sdram->emc_cfg_pipe << 12 >> 31 << 28) | ((sdram->emc_einput << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 & 0x7FF | (pmc->scratch151 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch152 = (32 * sdram->emc_cfg_pipe >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 6 >> 31 << 30) | ((sdram->emc_cfg_pipe << 7 >> 31 << 29) | ((sdram->emc_cfg_pipe << 8 >> 31 << 28) | ((sdram->emc_einput_duration << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 & 0x7FF | (pmc->scratch152 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch153 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 31) >> 2) | ((16 * sdram->emc_cfg_pipe >> 31 << 28) | ((sdram->emc_puterm_extra << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch153 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch154 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 26) >> 31 << 30) | (((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 28) >> 31 << 28) | ((sdram->emc_tckesr << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch154 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 27) >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch155 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 24) >> 31 << 28) | ((sdram->emc_tpd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch155 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch156 = (sdram->emc_pmacro_tx_sel_clk_src0 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 15 >> 31 << 28) | ((sdram->emc_wdv_mask << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch156 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch157 = (sdram->emc_pmacro_tx_sel_clk_src0 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 11 >> 31 << 28) | (((u16)(sdram->emc_wdv_chk) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 & 0x7FF | (pmc->scratch157 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch158 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src0 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 7 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft0) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft0) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 & 0x7FF | (pmc->scratch158 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch159 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 27) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 28) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 29) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 30) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft1) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft1) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch159 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch160 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 23) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 24) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 25) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 26) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft2) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft2) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch160 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch161 = (sdram->emc_pmacro_tx_sel_clk_src1 << 14 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 15 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 21 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 22 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft3) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch161 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch162 = (sdram->emc_pmacro_tx_sel_clk_src1 << 10 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 11 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 12 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 13 >> 31 << 28) | (((u16)(sdram->emc_wev) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch162 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch163 = (sdram->emc_pmacro_tx_sel_clk_src1 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 7 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 8 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 9 >> 31 << 28) | (((u16)(sdram->emc_wsv) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch163 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch164 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 31) >> 2) | ((32 * sdram->emc_pmacro_tx_sel_clk_src1 >> 31 << 28) | (((u8)(sdram->emc_cfg3) << 25 >> 29 << 25) | (((u8)(sdram->emc_cfg3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch164 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch165 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 26) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 27) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 28) >> 31 << 28) | ((sdram->emc_puterm_width << 23) & 0xFFFFFFF | ((sdram->emc_puterm_width >> 31 << 22) | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch165 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xF07FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch166 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 24) >> 31 << 28) | ((sdram->mc_emem_arb_timing_rcd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch166 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch167 = (sdram->emc_pmacro_tx_sel_clk_src3 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 15 >> 31 << 28) | (((u16)(sdram->mc_emem_arb_timing_ccdmw) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ddll_long_cmd_0 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_0 & 0x7FF | (pmc->scratch167 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch168 = (sdram->emc_pmacro_tx_sel_clk_src3 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 11 >> 31 << 28) | ((sdram->mc_emem_arb_override << 28 >> 31 << 27) | (((sdram->mc_emem_arb_override << 21 >> 31 << 25) | ((sdram->mc_emem_arb_override << 15 >> 31 << 24) | ((32 * sdram->mc_emem_arb_override >> 31 << 23) | ((16 * sdram->mc_emem_arb_override >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_1 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_1 & 0x7FF | (pmc->scratch168 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF | (sdram->mc_emem_arb_override << 27 >> 31 << 26)) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch169 = ((u16)(sdram->emc_rext) << 27) | (((u16)(sdram->emc_rrd) << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_2 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_2 & 0x7FF | (pmc->scratch169 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; + pmc->scratch170 = ((u16)(sdram->emc_wext) << 27) | ((sdram->emc_tclkstop << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_3 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_3 & 0x7FF | (pmc->scratch170 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; + tmp = (32 * sdram->emc_pmacro_perbit_fgcg_ctrl0 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl0 & 1 | 2 * (pmc->scratch171 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF; + pmc->scratch171 = (sdram->emc_we_duration << 27) | ((sdram->emc_ref_ctrl2 >> 31 << 26) | ((32 * sdram->emc_ref_ctrl2 >> 29 << 23) | ((sdram->emc_ref_ctrl2 << 22) & 0x7FFFFF | tmp & 0xFFBFFFFF) & 0xFC7FFFFF) & 0xFBFFFFFF) & 0x7FFFFFF; + tmp = (sdram->emc_pmacro_pad_cfg_ctrl << 22 >> 31 << 28) | ((sdram->emc_pmacro_pad_cfg_ctrl << 27) & 0xFFFFFFF | ((sdram->emc_ws_duration << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl1 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl1 & 1 | 2 * (pmc->scratch172 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; + pmc->scratch172 = (sdram->emc_pmacro_pad_cfg_ctrl << 14 >> 30 << 30) | (4 * ((sdram->emc_pmacro_pad_cfg_ctrl << 18 >> 31 << 29) | tmp & 0xDFFFFFFF) >> 2); + pmc->scratch173 = ((u8)(sdram->mc_emem_arb_timing_r2r) << 27) | ((sdram->mc_emem_arb_timing_rrd << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl2 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl2 & 1 | 2 * (pmc->scratch173 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0x7FFFFFF; + tmp = 32 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl3 & 1 | 2 * (pmc->scratch174 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; + pmc->scratch174 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30 >> 31 << 31) | (2 * (((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30) | ((32 * sdram->emc_pmacro_tx_sel_clk_src3 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 6 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 7 >> 31 << 27) | (((u8)(sdram->mc_emem_arb_timing_w2w) << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl3 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 25 >> 31 << 6) | tmp & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 28 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 29 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl4 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl4 & 1 | 2 * (pmc->scratch175 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF; + pmc->scratch175 = (sdram->emc_pmacro_tx_sel_clk_src2 << 15 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 21 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 22 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 23 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 24 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 25 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 26 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 27 >> 31 << 24) | tmp & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 12 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 13 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 14 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl5 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl5 & 1 | 2 * (pmc->scratch176 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; + pmc->scratch176 = (32 * sdram->emc_pmacro_tx_sel_clk_src2 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 6 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 8 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 9 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 10 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 11 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch177 = (sdram->emc_pmacro_tx_sel_clk_src4 << 22 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 23 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 24 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 25 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 26 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 27 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 28 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 29 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 30 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 22) & 0x7FFFFF | ((sdram->mc_emem_arb_cfg >> 28 << 18) | ((16 * sdram->mc_emem_arb_cfg >> 28 << 14) | ((sdram->mc_emem_arb_cfg << 11 >> 27 << 9) | (sdram->mc_emem_arb_cfg & 0x1FF | (pmc->scratch177 >> 9 << 9)) & 0xFFFFC1FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch178 = (sdram->emc_pmacro_tx_sel_clk_src4 << 7 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 8 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 9 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 10 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 11 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 12 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 13 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 14 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 15 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 21 >> 31 << 22) | ((sdram->mc_emem_arb_misc1 >> 28 << 18) | ((sdram->mc_emem_arb_misc1 << 6 >> 30 << 16) | ((sdram->mc_emem_arb_misc1 << 8 >> 29 << 13) | (16 * (sdram->mc_emem_arb_misc1 << 19 >> 23) | (8 * (sdram->mc_emem_arb_misc1 << 28 >> 31) | (4 * (sdram->mc_emem_arb_misc1 << 29 >> 31) | (2 * (sdram->mc_emem_arb_misc1 << 30 >> 31) | (sdram->mc_emem_arb_misc1 & 1 | 2 * (pmc->scratch178 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFE00F) & 0xFFFF1FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch179 = (sdram->emc_odt_write >> 31 << 31) | (2 * ((sdram->emc_odt_write << 20 >> 28 << 27) | ((sdram->emc_odt_write << 26 >> 31 << 26) | ((sdram->emc_odt_write << 27 >> 31 << 25) | ((sdram->emc_odt_write << 21) & 0x1FFFFFF | ((32 * sdram->emc_mrs_wait_cnt2 >> 21 << 10) | (sdram->emc_mrs_wait_cnt2 & 0x3FF | (pmc->scratch179 >> 10 << 10)) & 0xFFE003FF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->scratch180 = (sdram->emc_pmacro_ib_rxrt << 21) | ((32 * sdram->emc_mrs_wait_cnt >> 21 << 10) | (sdram->emc_mrs_wait_cnt & 0x3FF | (pmc->scratch180 >> 10 << 10)) & 0xFFE003FF) & 0x1FFFFF; + pmc->scratch181 = ((u16)(sdram->emc_pmacro_ddll_long_cmd_4) << 21) | sdram->emc_auto_cal_interval & 0x1FFFFF; + pmc->scratch182 = (sdram->mc_emem_arb_outstanding_req >> 31 << 31) | (2 * ((2 * sdram->mc_emem_arb_outstanding_req >> 31 << 30) | ((sdram->mc_emem_arb_outstanding_req << 23 >> 2) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 9 >> 25 << 14) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 17 >> 25 << 7) | (sdram->emc_emem_arb_refpb_hp_ctrl & 0x7F | (pmc->scratch182 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xC01FFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch183 = (4 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl0 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl0 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl0 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl0 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl0 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl0 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl0 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl0 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl0 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl0 << 20) & 0x1FFFFF | ((4 * sdram->emc_xm2_comp_pad_ctrl2 >> 26 << 14) | ((sdram->emc_xm2_comp_pad_ctrl2 << 10 >> 30 << 12) | ((sdram->emc_xm2_comp_pad_ctrl2 << 14 >> 31 << 11) | ((sdram->emc_xm2_comp_pad_ctrl2 << 15 >> 31 << 10) | ((sdram->emc_xm2_comp_pad_ctrl2 << 16 >> 30 << 8) | ((sdram->emc_xm2_comp_pad_ctrl2 << 18 >> 30 << 6) | (4 * (sdram->emc_xm2_comp_pad_ctrl2 << 26 >> 28) | (sdram->emc_xm2_comp_pad_ctrl2 & 3 | 4 * (pmc->scratch183 >> 2)) & 0xFFFFFFC3) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFF03FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch184 = (4 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl1 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl1 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl1 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl1 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl1 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl1 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl1 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl1 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl1 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl1 << 20) & 0x1FFFFF | ((sdram->emc_cfg_dig_dll_1 << 12 >> 28 << 16) | ((sdram->emc_cfg_dig_dll_1 << 16 >> 28 << 12) | ((sdram->emc_cfg_dig_dll_1 << 20 >> 26 << 6) | (2 * (sdram->emc_cfg_dig_dll_1 << 26 >> 27) | (sdram->emc_cfg_dig_dll_1 & 1 | 2 * (pmc->scratch184 >> 1)) & 0xFFFFFFC1) & 0xFFFFF03F) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch185 = (4 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl2 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl2 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl2 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl2 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl2 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl2 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl2 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl2 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl2 << 20) & 0x1FFFFF | ((sdram->emc_quse_brlshft0 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft0 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft0 << 22 >> 27) | (sdram->emc_quse_brlshft0 & 0x1F | 32 * (pmc->scratch185 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch186 = (sdram->emc_pmacro_dsr_vttgen_ctrl0 >> 8 << 24) | ((sdram->emc_pmacro_dsr_vttgen_ctrl0 << 20) | ((sdram->emc_quse_brlshft1 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft1 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft1 << 22 >> 27) | (sdram->emc_quse_brlshft1 & 0x1F | 32 * (pmc->scratch186 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFF0FFFFF) & 0xFFFFFF; + pmc->scratch187 = (sdram->emc_pmacro_perbit_rfu1_ctrl0 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft2 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft2 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft2 << 22 >> 27) | (sdram->emc_quse_brlshft2 & 0x1F | 32 * (pmc->scratch187 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch188 = (sdram->emc_pmacro_perbit_rfu1_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft3 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft3 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft3 << 22 >> 27) | (sdram->emc_quse_brlshft3 & 0x1F | 32 * (pmc->scratch188 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch189 = (sdram->emc_trefbw << 18) | ((sdram->emc_dbg >> 31 << 17) | ((2 * sdram->emc_dbg >> 31 << 16) | ((4 * sdram->emc_dbg >> 31 << 15) | ((8 * sdram->emc_dbg >> 31 << 14) | ((16 * sdram->emc_dbg >> 30 << 12) | ((sdram->emc_dbg << 6 >> 31 << 11) | ((sdram->emc_dbg << 7 >> 31 << 10) | ((sdram->emc_dbg << 18 >> 31 << 9) | ((sdram->emc_dbg << 19 >> 31 << 8) | ((sdram->emc_dbg << 20 >> 31 << 7) | ((sdram->emc_dbg << 21 >> 31 << 6) | (32 * (sdram->emc_dbg << 22 >> 31) | (16 * (sdram->emc_dbg << 27 >> 31) | (8 * (sdram->emc_dbg << 28 >> 31) | (4 * (sdram->emc_dbg << 29 >> 31) | (2 * (sdram->emc_dbg << 30 >> 31) | (sdram->emc_dbg & 1 | 2 * (pmc->scratch189 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0x3FFFF; + pmc->scratch191 = (sdram->emc_qpop << 9 >> 25 << 25) | ((sdram->emc_qpop << 18) | ((sdram->emc_zcal_wait_cnt >> 31 << 17) | ((sdram->emc_zcal_wait_cnt << 10 >> 26 << 11) | (sdram->emc_zcal_wait_cnt & 0x7FF | (pmc->scratch191 >> 11 << 11)) & 0xFFFE07FF) & 0xFFFDFFFF) & 0xFE03FFFF) & 0x1FFFFFF; + pmc->scratch192 = (sdram->emc_pmacro_tx_sel_clk_src4 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_auto_cal_common << 15 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_common << 18 >> 26 << 24) | ((sdram->emc_pmacro_auto_cal_common << 18) & 0xFFFFFF | ((sdram->emc_zcal_mrw_cmd >> 30 << 16) | ((sdram->emc_zcal_mrw_cmd << 8 >> 24 << 8) | (sdram->emc_zcal_mrw_cmd & 0xFF | (pmc->scratch192 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFCFFFF) & 0xFF03FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_dll_cfg1 << 7 >> 31 << 17) | ((sdram->emc_dll_cfg1 << 10 >> 31 << 16) | ((sdram->emc_dll_cfg1 << 11 >> 31 << 15) | ((sdram->emc_dll_cfg1 << 14 >> 30 << 13) | ((sdram->emc_dll_cfg1 << 18 >> 31 << 12) | ((sdram->emc_dll_cfg1 << 19 >> 31 << 11) | ((pmc->scratch193 >> 11 << 11) | sdram->emc_dll_cfg1 & 0x7FF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFF9FFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF; + pmc->scratch193 = (sdram->emc_pmacro_tx_sel_clk_src5 << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src4 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 18) & 0xFFFFF | tmp & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl2 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch194 = (sdram->emc_pmacro_tx_sel_clk_src5 << 29 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 30 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 14 >> 30 << 24) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 18) & 0xFFFFF | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_cmd_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch194 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 26 >> 30 << 22)) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch195 = (sdram->emc_pmacro_tx_sel_clk_src5 << 27 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 28 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 18) & 0xFFFFF | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_data_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch195 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl4 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch196 = (sdram->emc_emem_arb_refpb_bank_ctrl >> 31 << 31) | (2 * ((sdram->emc_emem_arb_refpb_bank_ctrl << 17 >> 25 << 24) | ((sdram->emc_emem_arb_refpb_bank_ctrl << 17) & 0xFFFFFF | ((sdram->emc_dyn_self_ref_control >> 31 << 16) | (sdram->emc_dyn_self_ref_control & 0xFFFF | (pmc->scratch196 >> 16 << 16)) & 0xFFFEFFFF) & 0xFF01FFFF) & 0x80FFFFFF) >> 1); + pmc->scratch197 = (sdram->emc_pmacro_tx_sel_clk_src5 << 24 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 25 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 26 >> 31 << 29) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 10 >> 30 << 27) | (((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 14 >> 30 << 23) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 26 >> 30 << 21) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 28 >> 30 << 19) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 17) & 0x7FFFF | ((16 * sdram->emc_pmacro_cmd_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_cmd_pad_rx_ctrl & 3 | 4 * (pmc->scratch197 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFF9FFFF) & 0xFFE7FFFF) & 0xFF9FFFFF) & 0xFE7FFFFF) & 0xF9FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl5 << 12 >> 30 << 25)) & 0xE7FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch198 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src5 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 7 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 8 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 9 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 10 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 11 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 12 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 13 >> 31 << 22) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 14 >> 31 << 21) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 15 >> 31 << 20) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 21 >> 31 << 19) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 22 >> 31 << 18) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 23 >> 31 << 17) | ((16 * sdram->emc_pmacro_data_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_data_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_data_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_data_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_data_pad_rx_ctrl & 3 | 4 * (pmc->scratch198 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch199 = (8 * sdram->emc_cmd_q >> 27 << 27) | ((sdram->emc_cmd_q << 17 >> 29 << 24) | ((sdram->emc_cmd_q << 21 >> 29 << 21) | ((sdram->emc_cmd_q << 16) & 0x1FFFFF | (((u16)(sdram->emc_refresh) << 16 >> 22 << 6) | (sdram->emc_refresh & 0x3F | (pmc->scratch199 >> 6 << 6)) & 0xFFFF003F) & 0xFFE0FFFF) & 0xFF1FFFFF) & 0xF8FFFFFF) & 0x7FFFFFF; + pmc->scratch210 = (sdram->emc_auto_cal_vref_sel1 << 16 >> 31 << 31) | (2 * ((sdram->emc_auto_cal_vref_sel1 << 17 >> 25 << 24) | ((sdram->emc_auto_cal_vref_sel1 << 24 >> 31 << 23) | ((sdram->emc_auto_cal_vref_sel1 << 16) & 0x7FFFFF | (sdram->emc_acpd_control & 0xFFFF | (pmc->scratch210 >> 16 << 16)) & 0xFF80FFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + tmp = 8 * (sdram->emc_pmacro_auto_cal_cfg0 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg0 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg0 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg0 & 1 | 2 * (pmc->scratch211 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7; + tmp = (sdram->emc_pmacro_auto_cal_cfg1 << 7 >> 31 << 28) | ((sdram->emc_pmacro_auto_cal_cfg1 << 12 >> 31 << 27) | ((sdram->emc_pmacro_auto_cal_cfg1 << 13 >> 31 << 26) | ((sdram->emc_pmacro_auto_cal_cfg1 << 14 >> 31 << 25) | ((sdram->emc_pmacro_auto_cal_cfg1 << 15 >> 31 << 24) | ((sdram->emc_pmacro_auto_cal_cfg1 << 20 >> 31 << 23) | ((sdram->emc_pmacro_auto_cal_cfg1 << 21 >> 31 << 22) | ((sdram->emc_pmacro_auto_cal_cfg1 << 22 >> 31 << 21) | ((sdram->emc_pmacro_auto_cal_cfg1 << 23 >> 31 << 20) | ((sdram->emc_pmacro_auto_cal_cfg1 << 28 >> 31 << 19) | ((sdram->emc_pmacro_auto_cal_cfg1 << 29 >> 31 << 18) | ((sdram->emc_pmacro_auto_cal_cfg1 << 30 >> 31 << 17) | ((sdram->emc_pmacro_auto_cal_cfg1 << 16) & 0x1FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg0 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg0 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg0 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg0 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg0 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg0 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg0 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg0 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg0 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg0 << 23 >> 31) | tmp & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; + pmc->scratch211 = (16 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 31) | (2 * ((32 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_cfg1 << 6 >> 31 << 29) | tmp & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch212 = (sdram->emc_xm2_comp_pad_ctrl3 << 8 >> 28 << 28) | ((sdram->emc_xm2_comp_pad_ctrl3 << 14 >> 31 << 27) | ((sdram->emc_xm2_comp_pad_ctrl3 << 15 >> 31 << 26) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16 >> 30 << 24) | ((sdram->emc_xm2_comp_pad_ctrl3 << 18 >> 30 << 22) | ((sdram->emc_xm2_comp_pad_ctrl3 << 26 >> 28 << 18) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16) & 0x3FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg2 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg2 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg2 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg2 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg2 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg2 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg2 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg2 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg2 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg2 << 23 >> 31) | (8 * (sdram->emc_pmacro_auto_cal_cfg2 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg2 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg2 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg2 & 1 | 2 * (pmc->scratch212 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; + pmc->scratch213 = ((u16)(sdram->emc_prerefresh_req_cnt) << 16) | (u16)(sdram->emc_cfg_dig_dll_period); + pmc->scratch214 = (sdram->emc_pmacro_data_pi_ctrl << 10 >> 26 << 26) | ((sdram->emc_pmacro_data_pi_ctrl << 19 >> 31 << 25) | ((sdram->emc_pmacro_data_pi_ctrl << 20 >> 28 << 21) | ((sdram->emc_pmacro_data_pi_ctrl << 27 >> 31 << 20) | ((sdram->emc_pmacro_data_pi_ctrl << 16) & 0xFFFFF | ((sdram->emc_pmacro_ddll_bypass >> 31 << 15) | ((2 * sdram->emc_pmacro_ddll_bypass >> 31 << 14) | ((4 * sdram->emc_pmacro_ddll_bypass >> 31 << 13) | ((16 * sdram->emc_pmacro_ddll_bypass >> 31 << 12) | ((32 * sdram->emc_pmacro_ddll_bypass >> 31 << 11) | ((sdram->emc_pmacro_ddll_bypass << 6 >> 31 << 10) | ((sdram->emc_pmacro_ddll_bypass << 7 >> 31 << 9) | ((sdram->emc_pmacro_ddll_bypass << 15 >> 31 << 8) | ((sdram->emc_pmacro_ddll_bypass << 16 >> 31 << 7) | ((sdram->emc_pmacro_ddll_bypass << 17 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_bypass << 18 >> 31) | (16 * (sdram->emc_pmacro_ddll_bypass << 20 >> 31) | (8 * (sdram->emc_pmacro_ddll_bypass << 21 >> 31) | (4 * (sdram->emc_pmacro_ddll_bypass << 22 >> 31) | (2 * (sdram->emc_pmacro_ddll_bypass << 23 >> 31) | (sdram->emc_pmacro_ddll_bypass & 1 | 2 * (pmc->scratch214 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + pmc->scratch215 = (sdram->emc_pmacro_cmd_pi_ctrl << 10 >> 26 << 10) | ((sdram->emc_pmacro_cmd_pi_ctrl << 19 >> 31 << 9) | (32 * (sdram->emc_pmacro_cmd_pi_ctrl << 20 >> 28) | (16 * (sdram->emc_pmacro_cmd_pi_ctrl << 27 >> 31) | (sdram->emc_pmacro_cmd_pi_ctrl & 0xF | 16 * (pmc->scratch215 >> 4)) & 0xFFFFFFEF) & 0xFFFFFE1F) & 0xFFFFFDFF) & 0xFFFF03FF; + tmp = (sdram->emc_pmacro_data_pad_tx_ctrl << 7 >> 31 << 24) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 8 >> 31 << 23) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 9 >> 31 << 22) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 10 >> 31 << 21) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15 >> 31 << 20) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 16 >> 31 << 19) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 21 >> 31 << 18) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 25 >> 31 << 17) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 26 >> 31 << 16) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15) & 0xFFFF | ((2 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 14) | ((4 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 13) | ((8 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 12) | ((16 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 11) | ((32 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 6 >> 31 << 9) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 7 >> 31 << 8) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 8 >> 31 << 7) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 9 >> 31 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 10 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 15 >> 31) | (8 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 16 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 21 >> 31) | (2 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 25 >> 31) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 26 >> 31) | 2 * (pmc->scratch216 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; -// s(emc_clock_source, 7:0, scratch6, 15:8); -// s(emc_clock_source_dll, 7:0, scratch6, 23:16); -// s(emc_clock_source, 31:29, scratch6, 26:24); -// s(emc_clock_source_dll, 31:29, scratch6, 29:27); -// s(emc_clock_source_dll, 11:10, scratch6, 31:30); -// pmc->scratch7 = (sdram->emc_rc << 24) | ((sdram->emc_zqcal_lpddr4_warm_boot << 27 >> 31 << 23) | ((sdram->emc_zqcal_lpddr4_warm_boot << 30 >> 31 << 22) | ((sdram->emc_zqcal_lpddr4_warm_boot << 21) & 0x3FFFFF | ((sdram->clk_rst_pllm_misc20_override << 20) & 0x1FFFFF | ((sdram->clk_rst_pllm_misc20_override << 28 >> 31 << 19) | ((sdram->clk_rst_pllm_misc20_override << 27 >> 31 << 18) | ((sdram->clk_rst_pllm_misc20_override << 26 >> 31 << 17) | ((sdram->clk_rst_pllm_misc20_override << 21 >> 31 << 16) | ((sdram->clk_rst_pllm_misc20_override << 20 >> 31 << 15) | ((sdram->clk_rst_pllm_misc20_override << 19 >> 31 << 14) | ((sdram->clk_rst_pllm_misc20_override << 18 >> 31 << 13) | ((sdram->emc_clock_source << 15 >> 31 << 12) | ((sdram->emc_clock_source << 11 >> 31 << 11) | ((sdram->emc_clock_source << 12 >> 31 << 10) | ((sdram->emc_clock_source << 6 >> 31 << 9) | ((sdram->emc_clock_source << 16 >> 31 << 8) | ((32 * sdram->emc_clock_source >> 31 << 7) | ((16 * sdram->emc_clock_source >> 31 << 6) | (16 * (sdram->emc_zqcal_lpddr4_warm_boot >> 30) | (4 * (sdram->clk_rst_pllm_misc20_override << 29 >> 30) | ((sdram->clk_rst_pllm_misc20_override << 22 >> 30) | 4 * (pmc->scratch7 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFFFFFF; -// pmc->scratch8 = (sdram->emc_pmacro_bg_bias_ctrl0 << 18 >> 30 << 30) | ((4 * pmc->scratch8) >> 2); -// pmc->scratch14 = ((u8)(sdram->emc_cfg_pipe_clk) << 31) | (2 * (((u8)(sdram->emc_fdpd_ctrl_cmd_no_ramp) << 30) | pmc->scratch14 & 0xBFFFFFFF) >> 1); -// s(emc_qrst, 6:0, scratch15, 26:20); -// s(emc_qrst, 20:16, scratch15, 31:27); -// s(emc_pmacro_cmd_tx_drive, 5:0, scratch16, 25:20); -// s(emc_pmacro_cmd_tx_drive, 13:8, scratch16, 31:26); -// pmc->scratch17 = (16 * sdram->emc_fbio_cfg8 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg8 >> 31 << 30) | ((sdram->emc_fbio_cfg8 << 6 >> 31 << 29) | ((sdram->emc_fbio_cfg8 << 7 >> 31 << 28) | ((sdram->emc_fbio_cfg8 << 8 >> 31 << 27) | ((sdram->emc_fbio_cfg8 << 9 >> 31 << 26) | ((sdram->emc_fbio_cfg8 << 10 >> 31 << 25) | ((sdram->emc_fbio_cfg8 << 11 >> 31 << 24) | ((sdram->emc_fbio_cfg8 << 12 >> 31 << 23) | ((sdram->emc_fbio_cfg8 << 13 >> 31 << 22) | ((sdram->emc_fbio_cfg8 << 14 >> 31 << 21) | ((sdram->emc_fbio_cfg8 << 15 >> 31 << 20) | pmc->scratch17 & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch18 = ((u16)(sdram->emc_txsr_dll) << 20) | pmc->scratch18 & 0xFFFFF; -// pmc->scratch19 = (sdram->emc_txdsrvttgen << 20) | pmc->scratch19 & 0xFFFFF; -// s32(emc_cfg_rsv, scratch22); -// s32(emc_auto_cal_config, scratch23); -// s32(emc_auto_cal_vref_sel0, scratch24); -// s32(emc_pmacro_brick_ctrl_rfu1, scratch25); -// s32(emc_pmacro_brick_ctrl_rfu2, scratch26); -// s32(emc_pmc_scratch1, scratch27); -// s32(emc_pmc_scratch2, scratch28); -// s32(emc_pmc_scratch3, scratch29); -// pmc->scratch30 = (sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl0 & 3 | 4 * (pmc->scratch30 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch31 = (sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl1 & 3 | 4 * (pmc->scratch31 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch32 = (sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl2 & 3 | 4 * (pmc->scratch32 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch33 = (sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl3 & 3 | 4 * (pmc->scratch33 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch40 = (sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl4 & 3 | 4 * (pmc->scratch40 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch42 = (sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl5 & 3 | 4 * (pmc->scratch42 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch44 = (sdram->mc_emem_arb_da_turns >> 24 << 24) | ((sdram->mc_emem_arb_da_turns >> 16 << 16) | ((sdram->mc_emem_arb_da_turns << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_turns & 0xFF | (pmc->scratch44 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; -// pmc->scratch64 = ((u16)(sdram->mc_emem_arb_misc2) << 31) | (2 * ((sdram->emc_fbio_spare << 30) | ((sdram->emc_fbio_spare << 24 >> 26 << 24) | ((sdram->emc_fbio_spare << 16 >> 24 << 16) | ((sdram->emc_fbio_spare << 8 >> 24 << 8) | ((sdram->emc_fbio_spare >> 24) | (pmc->scratch64 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch65 = ((u16)(sdram->mc_da_cfg0) << 31 >> 1) | ((2 * sdram->mc_emem_arb_misc0 >> 29 << 27) | ((16 * sdram->mc_emem_arb_misc0 >> 31 << 26) | ((32 * sdram->mc_emem_arb_misc0 >> 26 << 20) | ((sdram->mc_emem_arb_misc0 << 11 >> 27 << 15) | ((sdram->mc_emem_arb_misc0 << 17 >> 25 << 8) | ((u8)sdram->mc_emem_arb_misc0 | (pmc->scratch65 >> 8 << 8)) & 0xFFFF80FF) & 0xFFF07FFF) & 0xFC0FFFFF) & 0xFBFFFFFF) & 0xC7FFFFFF) & 0xBFFFFFFF; -// pmc->scratch66 = (sdram->emc_fdpd_ctrl_cmd >> 30 << 27) | ((4 * sdram->emc_fdpd_ctrl_cmd >> 31 << 26) | ((8 * sdram->emc_fdpd_ctrl_cmd >> 27 << 21) | ((sdram->emc_fdpd_ctrl_cmd << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_cmd << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_cmd << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_cmd | (pmc->scratch66 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xFBFFFFFF) & 0xE7FFFFFF; -// pmc->scratch67 = ((u8)(sdram->emc_burst_refresh_num) << 28) | ((16 * sdram->emc_auto_cal_config2 >> 30 << 26) | ((sdram->emc_auto_cal_config2 << 6 >> 30 << 24) | ((sdram->emc_auto_cal_config2 << 8 >> 30 << 22) | ((sdram->emc_auto_cal_config2 << 10 >> 30 << 20) | ((sdram->emc_auto_cal_config2 << 12 >> 30 << 18) | ((sdram->emc_auto_cal_config2 << 14 >> 30 << 16) | ((sdram->emc_auto_cal_config2 << 16 >> 30 << 14) | ((sdram->emc_auto_cal_config2 << 18 >> 30 << 12) | ((sdram->emc_auto_cal_config2 << 20 >> 30 << 10) | ((sdram->emc_auto_cal_config2 << 22 >> 30 << 8) | ((sdram->emc_auto_cal_config2 << 24 >> 30 << 6) | (16 * (sdram->emc_auto_cal_config2 << 26 >> 30) | (4 * (sdram->emc_auto_cal_config2 << 28 >> 30) | (sdram->emc_auto_cal_config2 & 3 | 4 * (pmc->scratch67 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; -// pmc->scratch68 = ((u8)(sdram->emc_tppd) << 28) | ((sdram->emc_cfg_dig_dll >> 31 << 27) | ((2 * sdram->emc_cfg_dig_dll >> 31 << 26) | ((16 * sdram->emc_cfg_dig_dll >> 31 << 25) | ((sdram->emc_cfg_dig_dll << 6 >> 22 << 15) | ((sdram->emc_cfg_dig_dll << 16 >> 31 << 14) | ((sdram->emc_cfg_dig_dll << 17 >> 31 << 13) | ((sdram->emc_cfg_dig_dll << 18 >> 30 << 11) | ((sdram->emc_cfg_dig_dll << 21 >> 29 << 8) | ((sdram->emc_cfg_dig_dll << 24 >> 30 << 6) | (32 * (sdram->emc_cfg_dig_dll << 26 >> 31) | (16 * (sdram->emc_cfg_dig_dll << 27 >> 31) | (8 * (sdram->emc_cfg_dig_dll << 28 >> 31) | (4 * (sdram->emc_cfg_dig_dll << 29 >> 31) | (2 * (sdram->emc_cfg_dig_dll << 30 >> 31) | (sdram->emc_cfg_dig_dll & 1 | 2 * (pmc->scratch68 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFF3F) & 0xFFFFF8FF) & 0xFFFFE7FF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFE007FFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; -// pmc->scratch69 = (sdram->emc_r2r << 28) | ((sdram->emc_fdpd_ctrl_dq >> 30 << 26) | ((8 * sdram->emc_fdpd_ctrl_dq >> 27 << 21) | ((sdram->emc_fdpd_ctrl_dq << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_dq << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_dq << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_dq | (pmc->scratch69 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; -// pmc->scratch70 = (sdram->emc_w2w << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_0 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ib_vref_dq_0 & 0x7F | (pmc->scratch70 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; -// pmc->scratch71 = (sdram->emc_pmacro_vttgen_ctrl0 << 12 >> 28 << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_1 << 17 >> 25 << 7) | ((pmc->scratch71 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dq_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; -// pmc->scratch72 = (((sdram->emc_pmacro_ib_vref_dqs_0 << 17 >> 25 << 7) | ((pmc->scratch72 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_0 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF | (sdram->emc_pmacro_ib_vref_dqs_0 << 9 >> 25 << 14)) & 0xF01FFFFF | (2 * sdram->emc_pmacro_ib_vref_dqs_0 >> 25 << 21); -// pmc->scratch73 = (2 * sdram->emc_pmacro_ib_vref_dqs_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 17 >> 25 << 7) | ((pmc->scratch73 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; -// pmc->scratch74 = (2 * sdram->emc_pmacro_ddll_short_cmd_0 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_0 & 0x7F | (pmc->scratch74 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; -// pmc->scratch75 = (2 * sdram->emc_pmacro_ddll_short_cmd_1 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_1 & 0x7F | (pmc->scratch75 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; -// pmc->scratch76 = (sdram->emc_rp << 26) | ((4 * sdram->emc_dll_cfg0 >> 31 << 25) | ((8 * sdram->emc_dll_cfg0 >> 31 << 24) | ((16 * sdram->emc_dll_cfg0 >> 28 << 20) | ((sdram->emc_dll_cfg0 << 8 >> 28 << 16) | ((sdram->emc_dll_cfg0 << 12 >> 28 << 12) | ((sdram->emc_dll_cfg0 << 16 >> 28 << 8) | ((sdram->emc_dll_cfg0 << 20 >> 24) | (pmc->scratch76 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; -// tmp = (sdram->emc_pmacro_tx_pwrd0 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd0 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd0 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd0 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd0 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd0 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd0 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd0 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd0 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd0 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd0 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd0 & 1 | 2 * (pmc->scratch77 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF; -// pmc->scratch77 = (sdram->emc_r2w << 26) | ((4 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd0 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd0 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd0 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd0 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd0 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd0 << 11 >> 31 << 17) | tmp & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; -// tmp = ((8 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd1 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd1 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd1 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd1 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd1 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd1 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd1 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd1 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd1 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd1 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd1 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd1 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd1 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd1 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd1 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd1 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd1 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd1 & 1 | 2 * (pmc->scratch78 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; -// pmc->scratch78 = (sdram->emc_w2r << 26) | ((4 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 25) | tmp) & 0x3FFFFFF; -// tmp = ((8 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd2 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd2 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd2 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd2 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd2 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd2 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd2 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd2 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd2 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd2 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd2 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd2 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd2 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd2 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd2 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd2 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd2 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd2 & 1 | 2 * (pmc->scratch79 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; -// pmc->scratch79 = (sdram->emc_r2p << 26) | ((4 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 25) | tmp) & 0x3FFFFFF; -// tmp = (sdram->emc_pmacro_tx_pwrd3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd3 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd3 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd3 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd3 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd3 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd3 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd3 & 1 | 2 * (pmc->scratch80 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF; -// pmc->scratch80 = ((u8)(sdram->emc_ccdmw) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd3 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd3 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd3 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd3 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd3 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd3 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd3 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd3 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd3 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd3 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd3 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd3 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd3 << 22 >> 31 << 9) | tmp & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; -// tmp = ((8 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd4 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd4 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd4 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd4 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd4 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd4 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd4 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd4 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd4 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd4 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd4 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd4 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd4 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd4 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd4 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd4 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd4 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd4 & 1 | 2 * (pmc->scratch81 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; -// pmc->scratch81 = ((u8)(sdram->emc_rd_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 25) | tmp) & 0x3FFFFFF; -// tmp = ((8 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd5 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd5 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd5 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd5 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd5 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd5 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd5 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd5 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd5 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd5 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd5 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd5 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd5 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd5 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd5 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd5 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd5 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd5 & 1 | 2 * (pmc->scratch82 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; -// pmc->scratch82 = ((u16)(sdram->emc_wr_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 25) | tmp) & 0x3FFFFFF; -// pmc->scratch83 = ((u8)(sdram->emc_config_sample_delay) << 25) | ((sdram->emc_auto_cal_channel >> 31 << 24) | ((2 * sdram->emc_auto_cal_channel >> 31 << 23) | ((4 * sdram->emc_auto_cal_channel >> 31 << 22) | ((16 * sdram->emc_auto_cal_channel >> 25 << 15) | ((sdram->emc_auto_cal_channel << 11 >> 27 << 10) | ((sdram->emc_auto_cal_channel << 20 >> 28 << 6) | (sdram->emc_auto_cal_channel & 0x3F | (pmc->scratch83 >> 6 << 6)) & 0xFFFFFC3F) & 0xFFFF83FF) & 0xFFC07FFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0x1FFFFFF; -// pmc->scratch84 = (sdram->emc_sel_dpd_ctrl << 13 >> 29 << 29) | ((sdram->emc_sel_dpd_ctrl << 23 >> 31 << 28) | ((sdram->emc_sel_dpd_ctrl << 26 >> 31 << 27) | ((sdram->emc_sel_dpd_ctrl << 27 >> 31 << 26) | ((sdram->emc_sel_dpd_ctrl << 28 >> 31 << 25) | ((sdram->emc_sel_dpd_ctrl << 29 >> 31 << 24) | ((4 * sdram->emc_pmacro_rx_term >> 26 << 18) | ((sdram->emc_pmacro_rx_term << 10 >> 26 << 12) | ((sdram->emc_pmacro_rx_term << 18 >> 26 << 6) | (sdram->emc_pmacro_rx_term & 0x3F | (pmc->scratch84 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; -// pmc->scratch85 = (4 * sdram->emc_obdly >> 30 << 30) | (4 * ((sdram->emc_obdly << 24) | ((4 * sdram->emc_pmacro_dq_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_dq_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_dq_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_dq_tx_drive & 0x3F | (pmc->scratch85 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); -// pmc->scratch86 = (sdram->emc_pmacro_vttgen_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_vttgen_ctrl1 << 16 >> 26 << 24) | ((4 * sdram->emc_pmacro_ca_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_ca_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_ca_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_ca_tx_drive & 0x3F | (pmc->scratch86 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); -// pmc->scratch87 = (sdram->emc_pmacro_vttgen_ctrl2 >> 16 << 24) | ((16 * sdram->emc_pmacro_zcrtl >> 30 << 22) | ((sdram->emc_pmacro_zcrtl << 6 >> 30 << 20) | ((sdram->emc_pmacro_zcrtl << 8 >> 30 << 18) | ((sdram->emc_pmacro_zcrtl << 10 >> 30 << 16) | ((sdram->emc_pmacro_zcrtl << 12 >> 30 << 14) | ((sdram->emc_pmacro_zcrtl << 14 >> 30 << 12) | ((sdram->emc_pmacro_zcrtl << 16 >> 30 << 10) | ((sdram->emc_pmacro_zcrtl << 18 >> 30 << 8) | ((sdram->emc_pmacro_zcrtl << 20 >> 30 << 6) | (16 * (sdram->emc_pmacro_zcrtl << 22 >> 30) | (4 * (sdram->emc_pmacro_zcrtl << 24 >> 30) | ((sdram->emc_pmacro_zcrtl << 26 >> 30) | 4 * (pmc->scratch87 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFFFFFF; -// pmc->scratch88 = (sdram->mc_emem_arb_timing_rc << 24) | ((sdram->emc_zcal_interval << 14) | ((sdram->emc_zcal_interval << 8 >> 18) | (pmc->scratch88 >> 14 << 14)) & 0xFF003FFF) & 0xFFFFFF; -// pmc->scratch89 = ((u16)(sdram->mc_emem_arb_rsv) << 24) | ((sdram->emc_data_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft0 << 26 >> 29) | (sdram->emc_data_brlshft0 & 7 | 8 * (pmc->scratch89 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0xFFFFFF; -// pmc->scratch90 = (sdram->emc_data_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft1 << 26 >> 29) | (sdram->emc_data_brlshft1 & 7 | 8 * (pmc->scratch90 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; -// pmc->scratch91 = (sdram->emc_dqs_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft0 << 26 >> 29) | (sdram->emc_dqs_brlshft0 & 7 | 8 * (pmc->scratch91 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; -// pmc->scratch92 = (sdram->emc_dqs_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft1 << 26 >> 29) | (sdram->emc_dqs_brlshft1 & 7 | 8 * (pmc->scratch92 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; -// pmc->scratch93 = (2 * sdram->emc_swizzle_rank0_byte0 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte0 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte0 & 7 | 8 * (pmc->scratch93 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; -// pmc->scratch94 = ((u8)(sdram->emc_cfg) << 27 >> 31 << 31) | (2 * ((sdram->emc_ras << 24) | ((2 * sdram->emc_swizzle_rank0_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte1 & 7 | 8 * (pmc->scratch94 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch95 = ((u8)(sdram->emc_cfg) << 26 >> 31 << 31) | (2 * ((sdram->emc_w2p << 24) | ((2 * sdram->emc_swizzle_rank0_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte2 & 7 | 8 * (pmc->scratch95 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch96 = ((u8)(sdram->emc_cfg) << 25 >> 31 << 31) | (2 * ((sdram->emc_qsafe << 24) | ((2 * sdram->emc_swizzle_rank0_byte3 >> 29 << 21) | (((sdram->emc_swizzle_rank0_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte3 & 7 | 8 * (pmc->scratch96 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank0_byte3 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch97 = ((u8)(sdram->emc_cfg) << 24 >> 31 << 31) | (2 * ((sdram->emc_rdv << 24) | ((2 * sdram->emc_swizzle_rank1_byte0 >> 29 << 21) | (((sdram->emc_swizzle_rank1_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte0 & 7 | 8 * (pmc->scratch97 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank1_byte0 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch98 = ((u16)(sdram->emc_cfg) << 23 >> 31 << 31) | (2 * (((u16)(sdram->emc_rw2pden) << 24) | ((2 * sdram->emc_swizzle_rank1_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte1 & 7 | 8 * (pmc->scratch98 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch99 = ((u16)(sdram->emc_cfg) << 22 >> 31 << 31) | (2 * ((sdram->emc_tfaw << 24) | ((2 * sdram->emc_swizzle_rank1_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte2 & 7 | 8 * (pmc->scratch99 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch100 = (sdram->emc_cfg << 13 >> 31 << 31) | (2 * ((sdram->emc_tclkstable << 24) | ((2 * sdram->emc_swizzle_rank1_byte3 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte3 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte3 & 7 | 8 * (pmc->scratch100 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); -// tmp = 2 * (((u8)(sdram->emc_trtm) << 24) | ((16 * sdram->emc_cfg_pipe2 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe2 >> 31 << 22) | ((sdram->emc_cfg_pipe2 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe2 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe2 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe2 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe2 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe2 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe2 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe2 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe2 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe2 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe2 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe2 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe2 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe2 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe2 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe2 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe2 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe2 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe2 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe2 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe2 << 30 >> 31) | (sdram->emc_cfg_pipe2 & 1 | 2 * (pmc->scratch101 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; -// pmc->scratch101 = (sdram->emc_cfg << 10 >> 31 << 31) | tmp; -// tmp = (2 * (pmc->scratch102 >> 1) | sdram->emc_cfg_pipe1 & 1) & 0xFFFFFFFD; -// pmc->scratch102 = (sdram->emc_cfg << 9 >> 31 << 31) | (2 * (((u8)(sdram->emc_twtm) << 24) | ((16 * sdram->emc_cfg_pipe1 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe1 >> 31 << 22) | ((sdram->emc_cfg_pipe1 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe1 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe1 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe1 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe1 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe1 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe1 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe1 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe1 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe1 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe1 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe1 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe1 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe1 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe1 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe1 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe1 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe1 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe1 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe1 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe1 << 30 >> 31) | tmp) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); -// tmp = 2 * (((u8)(sdram->emc_tratm) << 24) | ((sdram->emc_pmacro_ddll_pwrd0 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd0 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd0 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd0 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd0 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd0 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd0 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd0 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd0 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd0 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd0 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd0 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd0 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd0 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd0 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd0 << 30 >> 31) | 2 * (pmc->scratch103 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; -// pmc->scratch103 = (sdram->emc_cfg << 8 >> 31 << 31) | tmp; -// tmp = 2 * (((u8)(sdram->emc_twatm) << 24) | ((sdram->emc_pmacro_ddll_pwrd1 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd1 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd1 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd1 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd1 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd1 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd1 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd1 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd1 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd1 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd1 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd1 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd1 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd1 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd1 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd1 << 30 >> 31) | 2 * (pmc->scratch104 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; -// pmc->scratch104 = (sdram->emc_cfg << 7 >> 31 << 31) | tmp; -// tmp = (sdram->emc_pmacro_ddll_pwrd2 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd2 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd2 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd2 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd2 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd2 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd2 << 30 >> 31) | 2 * (pmc->scratch105 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF; -// pmc->scratch105 = (sdram->emc_cfg << 6 >> 31 << 31) | (2 * (((u8)(sdram->emc_tr2ref) << 24) | ((sdram->emc_pmacro_ddll_pwrd2 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd2 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd2 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd2 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd2 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd2 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd2 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd2 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd2 << 21 >> 31 << 7) | tmp & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch106 = (32 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_pdex2mrr) << 24) | ((8 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 23) | ((16 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 21) | ((sdram->emc_pmacro_ddll_periodic_offset << 6 >> 31 << 20) | ((sdram->emc_pmacro_ddll_periodic_offset << 7 >> 31 << 19) | ((sdram->emc_pmacro_ddll_periodic_offset << 8 >> 31 << 18) | ((sdram->emc_pmacro_ddll_periodic_offset << 9 >> 31 << 17) | ((sdram->emc_pmacro_ddll_periodic_offset << 10 >> 31 << 16) | ((sdram->emc_pmacro_ddll_periodic_offset << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_periodic_offset << 15 >> 31 << 14) | ((sdram->emc_pmacro_ddll_periodic_offset << 16 >> 31 << 13) | ((sdram->emc_pmacro_ddll_periodic_offset << 17 >> 31 << 12) | ((sdram->emc_pmacro_ddll_periodic_offset << 18 >> 31 << 11) | ((sdram->emc_pmacro_ddll_periodic_offset << 19 >> 31 << 10) | ((sdram->emc_pmacro_ddll_periodic_offset << 20 >> 31 << 9) | ((sdram->emc_pmacro_ddll_periodic_offset << 21 >> 31 << 8) | ((sdram->emc_pmacro_ddll_periodic_offset << 22 >> 31 << 7) | ((sdram->emc_pmacro_ddll_periodic_offset << 23 >> 31 << 6) | (sdram->emc_pmacro_ddll_periodic_offset & 0x3F | (pmc->scratch106 >> 6 << 6)) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch107 = (8 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_clken_override << 15 >> 31 << 30) | ((sdram->emc_clken_override << 23 >> 31 << 29) | ((sdram->emc_clken_override << 24 >> 31 << 28) | ((sdram->emc_clken_override << 25 >> 31 << 27) | ((sdram->emc_clken_override << 28 >> 31 << 26) | ((sdram->emc_clken_override << 29 >> 31 << 25) | ((sdram->emc_clken_override << 30 >> 31 << 24) | ((sdram->mc_emem_arb_da_covers << 8 >> 24 << 16) | ((sdram->mc_emem_arb_da_covers << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_covers & 0xFF | (pmc->scratch107 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch108 = (sdram->emc_rfc_pb << 23) | ((sdram->emc_xm2_comp_pad_ctrl >> 24 << 15) | ((sdram->emc_xm2_comp_pad_ctrl << 12 >> 24 << 7) | ((sdram->emc_xm2_comp_pad_ctrl << 20 >> 31 << 6) | (32 * (sdram->emc_xm2_comp_pad_ctrl << 22 >> 31) | (4 * (sdram->emc_xm2_comp_pad_ctrl << 25 >> 29) | (sdram->emc_xm2_comp_pad_ctrl & 3 | 4 * (pmc->scratch108 >> 2)) & 0xFFFFFFE3) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFF807F) & 0xFF807FFF) & 0x7FFFFF; -// pmc->scratch109 = (sdram->emc_cfg_update >> 31 << 31) | (2 * ((2 * sdram->emc_cfg_update >> 31 << 30) | ((4 * sdram->emc_cfg_update >> 31 << 29) | ((8 * sdram->emc_cfg_update >> 31 << 28) | ((sdram->emc_cfg_update << 21 >> 30 << 26) | ((sdram->emc_cfg_update << 23 >> 31 << 25) | ((sdram->emc_cfg_update << 29 >> 30 << 23) | ((sdram->emc_cfg_update << 22) & 0x7FFFFF | ((sdram->emc_auto_cal_config3 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config3 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config3 << 17 >> 25 << 7) | ((pmc->scratch109 >> 7 << 7) | sdram->emc_auto_cal_config3 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFE7FFFFF) & 0xFDFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch110 = (sdram->emc_rfc << 22) | ((sdram->emc_auto_cal_config4 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config4 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config4 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config4 & 0x7F | (pmc->scratch110 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; -// pmc->scratch111 = ((u16)(sdram->emc_txsr) << 22) | ((sdram->emc_auto_cal_config5 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config5 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config5 << 17 >> 25 << 7) | ((pmc->scratch111 >> 7 << 7) | sdram->emc_auto_cal_config5 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; -// pmc->scratch112 = (16 * sdram->emc_mc2emc_q >> 28 << 28) | ((sdram->emc_mc2emc_q << 21 >> 29 << 25) | ((sdram->emc_mc2emc_q << 22) & 0x1FFFFFF | ((sdram->emc_auto_cal_config6 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config6 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config6 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config6 & 0x7F | (pmc->scratch112 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xFFFFFFF; -// pmc->scratch113 = (sdram->mc_emem_arb_ring1_throttle << 11 >> 27 << 27) | ((sdram->mc_emem_arb_ring1_throttle << 22) | ((sdram->emc_auto_cal_config7 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config7 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config7 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config7 & 0x7F | (pmc->scratch113 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xF83FFFFF) & 0x7FFFFFF; -// pmc->scratch114 = (sdram->emc_auto_cal_config8 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config8 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config8 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config8 & 0x7F | (pmc->scratch114 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF; -// pmc->scratch115 = (4 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_ar2pden) << 22) | ((sdram->emc_fbio_cfg7 << 10 >> 30 << 20) | ((sdram->emc_fbio_cfg7 << 12 >> 31 << 19) | ((sdram->emc_fbio_cfg7 << 13 >> 31 << 18) | ((sdram->emc_fbio_cfg7 << 14 >> 31 << 17) | ((sdram->emc_fbio_cfg7 << 15 >> 31 << 16) | ((sdram->emc_fbio_cfg7 << 16 >> 31 << 15) | ((sdram->emc_fbio_cfg7 << 17 >> 31 << 14) | ((sdram->emc_fbio_cfg7 << 18 >> 31 << 13) | ((sdram->emc_fbio_cfg7 << 19 >> 31 << 12) | ((sdram->emc_fbio_cfg7 << 20 >> 31 << 11) | ((sdram->emc_fbio_cfg7 << 21 >> 31 << 10) | ((sdram->emc_fbio_cfg7 << 22 >> 31 << 9) | ((sdram->emc_fbio_cfg7 << 23 >> 31 << 8) | ((sdram->emc_fbio_cfg7 << 24 >> 31 << 7) | ((sdram->emc_fbio_cfg7 << 25 >> 31 << 6) | (32 * (sdram->emc_fbio_cfg7 << 26 >> 31) | (16 * (sdram->emc_fbio_cfg7 << 27 >> 31) | (8 * (sdram->emc_fbio_cfg7 << 28 >> 31) | (4 * (sdram->emc_fbio_cfg7 << 29 >> 31) | (2 * (sdram->emc_fbio_cfg7 << 30 >> 31) | (sdram->emc_fbio_cfg7 & 1 | 2 * (pmc->scratch115 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFCFFFFF) & 0x803FFFFF) >> 1); -// pmc->scratch123 = (2 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_rfc_slr << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_0 & 0x7FF | (pmc->scratch123 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); -// pmc->scratch124 = (sdram->emc_cfg >> 31 << 31) | (2 * ((4 * sdram->emc_ibdly >> 30 << 29) | ((sdram->emc_ibdly << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_1 & 0x7FF | (pmc->scratch124 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); -// pmc->scratch125 = (sdram->emc_fbio_cfg5 << 27 >> 31 << 31) | (2 * (((u16)(sdram->mc_emem_arb_timing_rfcpb) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_2 & 0x7FF | (pmc->scratch125 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); -// pmc->scratch126 = (sdram->emc_fbio_cfg5 << 16 >> 29 << 29) | ((sdram->emc_auto_cal_config9 << 25 >> 31 << 28) | ((sdram->emc_auto_cal_config9 << 26 >> 31 << 27) | ((sdram->emc_auto_cal_config9 << 27 >> 31 << 26) | ((sdram->emc_auto_cal_config9 << 28 >> 31 << 25) | ((sdram->emc_auto_cal_config9 << 29 >> 31 << 24) | ((sdram->emc_auto_cal_config9 << 30 >> 31 << 23) | ((sdram->emc_auto_cal_config9 << 22) & 0x7FFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_3 & 0x7FF | (pmc->scratch126 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; -// pmc->scratch127 = ((u8)(sdram->emc_cfg2) << 26 >> 29 << 29) | ((sdram->emc_rdv_mask << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_4 & 0x7FF | (pmc->scratch127 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch128 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 27 >> 29 << 29) | (((u8)(sdram->emc_rdv_early_mask) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_5 & 0x7FF | (pmc->scratch128 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch129 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_rdv_early << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_0 & 0x7FF | (pmc->scratch129 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch130 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 17 >> 29 << 29) | ((4 * sdram->emc_quse_width >> 31 << 28) | ((8 * sdram->emc_quse_width >> 31 << 27) | ((sdram->emc_quse_width << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_1 & 0x7FF | (pmc->scratch130 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; -// pmc->scratch131 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 12 >> 29 << 29) | (((u16)(sdram->emc_pmacro_ddll_short_cmd_2) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_2 & 0x7FF | (pmc->scratch131 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch132 = (sdram->emc_pmacro_data_pad_tx_ctrl << 27 >> 29 << 29) | ((sdram->emc_pmacro_cmd_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_cmd_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_3 & 0x7FF | (pmc->scratch132 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; -// pmc->scratch133 = (sdram->emc_pmacro_data_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_pmacro_data_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_data_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_data_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_data_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_4 & 0x7FF | (pmc->scratch133 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; -// pmc->scratch134 = (sdram->emc_pmacro_data_pad_tx_ctrl << 17 >> 29 << 29) | ((sdram->mc_emem_arb_timing_rp << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_5 & 0x7FF | (pmc->scratch134 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch135 = (sdram->emc_pmacro_data_pad_tx_ctrl << 12 >> 29 << 29) | ((sdram->mc_emem_arb_timing_ras << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 & 0x7FF | (pmc->scratch135 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; -// pmc->scratch136 = (sdram->emc_fbio_cfg5 << 23 >> 31 << 31) | (2 * ((sdram->emc_cfg << 14 >> 30 << 29) | ((sdram->mc_emem_arb_timing_faw << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 & 0x7FF | (pmc->scratch136 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); -// pmc->scratch137 = (sdram->emc_fbio_cfg5 << 21 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 29) | ((sdram->mc_emem_arb_timing_rap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 & 0x7FF | (pmc->scratch137 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); -// pmc->scratch138 = (sdram->emc_fbio_cfg5 << 19 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 28 >> 30 << 29) | ((sdram->mc_emem_arb_timing_wap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 & 0x7FF | (pmc->scratch138 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); -// pmc->scratch139 = (sdram->emc_fbio_cfg5 << 7 >> 31 << 31) | (2 * ((16 * sdram->emc_cfg2 >> 30 << 29) | (((u8)(sdram->mc_emem_arb_timing_r2w) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 & 0x7FF | (pmc->scratch139 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); -// pmc->scratch140 = (16 * sdram->emc_fbio_cfg5 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg5 >> 31 << 30) | ((sdram->emc_fbio_cfg5 << 6 >> 31 << 29) | (((u8)(sdram->mc_emem_arb_timing_w2r) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 & 0x7FF | (pmc->scratch140 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch141 = (sdram->emc_fbio_cfg5 << 8 >> 28 << 28) | (((u16)(sdram->emc_wdv) << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 & 0x7FF | (pmc->scratch141 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xFFFFFFF; -// pmc->scratch142 = ((u8)(sdram->emc_cfg2) << 31) | (2 * ((sdram->emc_fbio_cfg5 >> 31 << 30) | ((2 * sdram->emc_fbio_cfg5 >> 31 << 29) | ((8 * sdram->emc_fbio_cfg5 >> 31 << 28) | ((sdram->emc_quse << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 & 0x7FF | (pmc->scratch142 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch143 = (((u16)(sdram->emc_cfg2) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg2) << 24) >> 31 << 30) | ((((u16)(sdram->emc_cfg2) << 29) >> 31 << 29) | ((((u16)(sdram->emc_cfg2) << 30) >> 31 << 28) | (((u8)(sdram->emc_pdex2wr) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 & 0x7FF | (pmc->scratch143 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch144 = (sdram->emc_cfg2 << 15 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 16 >> 31 << 30) | ((sdram->emc_cfg2 << 17 >> 31 << 29) | ((sdram->emc_cfg2 << 20 >> 31 << 28) | (((u8)(sdram->emc_pdex2rd) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 & 0x7FF | (pmc->scratch144 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch145 = (sdram->emc_cfg2 << 7 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 8 >> 31 << 30) | ((sdram->emc_cfg2 << 9 >> 31 << 29) | ((sdram->emc_cfg2 << 11 >> 31 << 28) | (((u16)(sdram->emc_pdex2che) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 & 0x7FF | (pmc->scratch145 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch146 = (2 * sdram->emc_cfg2 >> 31 << 31) | (2 * ((4 * sdram->emc_cfg2 >> 31 << 30) | (((sdram->emc_cfg2 << 6 >> 31 << 28) | (((u8)(sdram->emc_pchg2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 & 0x7FF | (pmc->scratch146 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (8 * sdram->emc_cfg2 >> 31 << 29)) & 0xBFFFFFFF) >> 1); -// pmc->scratch147 = (((u8)(sdram->emc_cfg_pipe) << 29) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 30) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 31) >> 2) | ((sdram->emc_cfg2 >> 31 << 28) | (((u16)(sdram->emc_act2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch147 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch148 = (((u8)(sdram->emc_cfg_pipe) << 25) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 26) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 27) >> 31 << 29) | ((((u8)(sdram->emc_cfg_pipe) << 28) >> 31 << 28) | (((u16)(sdram->emc_cke2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch148 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch149 = (((u16)(sdram->emc_cfg_pipe) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg_pipe) << 22) >> 31 << 30) | ((((u16)(sdram->emc_cfg_pipe) << 23) >> 31 << 29) | ((((u16)(sdram->emc_cfg_pipe) << 24) >> 31 << 28) | ((sdram->emc_tcke << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch149 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch150 = (sdram->emc_cfg_pipe << 13 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 14 >> 31 << 30) | (((sdram->emc_cfg_pipe << 20 >> 31 << 28) | ((sdram->emc_trpab << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch150 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (sdram->emc_cfg_pipe << 15 >> 31 << 29)) & 0xBFFFFFFF) >> 1); -// pmc->scratch151 = (sdram->emc_cfg_pipe << 9 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 10 >> 31 << 30) | ((sdram->emc_cfg_pipe << 11 >> 31 << 29) | ((sdram->emc_cfg_pipe << 12 >> 31 << 28) | ((sdram->emc_einput << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 & 0x7FF | (pmc->scratch151 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch152 = (32 * sdram->emc_cfg_pipe >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 6 >> 31 << 30) | ((sdram->emc_cfg_pipe << 7 >> 31 << 29) | ((sdram->emc_cfg_pipe << 8 >> 31 << 28) | ((sdram->emc_einput_duration << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 & 0x7FF | (pmc->scratch152 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch153 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 31) >> 2) | ((16 * sdram->emc_cfg_pipe >> 31 << 28) | ((sdram->emc_puterm_extra << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch153 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch154 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 26) >> 31 << 30) | (((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 28) >> 31 << 28) | ((sdram->emc_tckesr << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch154 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 27) >> 31 << 29)) & 0xBFFFFFFF) >> 1); -// pmc->scratch155 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 24) >> 31 << 28) | ((sdram->emc_tpd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch155 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch156 = (sdram->emc_pmacro_tx_sel_clk_src0 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 15 >> 31 << 28) | ((sdram->emc_wdv_mask << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch156 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch157 = (sdram->emc_pmacro_tx_sel_clk_src0 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 11 >> 31 << 28) | (((u16)(sdram->emc_wdv_chk) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 & 0x7FF | (pmc->scratch157 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch158 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src0 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 7 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft0) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft0) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 & 0x7FF | (pmc->scratch158 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch159 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 27) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 28) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 29) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 30) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft1) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft1) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch159 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch160 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 23) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 24) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 25) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 26) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft2) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft2) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch160 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch161 = (sdram->emc_pmacro_tx_sel_clk_src1 << 14 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 15 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 21 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 22 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft3) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch161 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch162 = (sdram->emc_pmacro_tx_sel_clk_src1 << 10 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 11 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 12 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 13 >> 31 << 28) | (((u16)(sdram->emc_wev) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch162 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch163 = (sdram->emc_pmacro_tx_sel_clk_src1 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 7 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 8 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 9 >> 31 << 28) | (((u16)(sdram->emc_wsv) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch163 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch164 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 31) >> 2) | ((32 * sdram->emc_pmacro_tx_sel_clk_src1 >> 31 << 28) | (((u8)(sdram->emc_cfg3) << 25 >> 29 << 25) | (((u8)(sdram->emc_cfg3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch164 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch165 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 26) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 27) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 28) >> 31 << 28) | ((sdram->emc_puterm_width << 23) & 0xFFFFFFF | ((sdram->emc_puterm_width >> 31 << 22) | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch165 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xF07FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch166 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 24) >> 31 << 28) | ((sdram->mc_emem_arb_timing_rcd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch166 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch167 = (sdram->emc_pmacro_tx_sel_clk_src3 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 15 >> 31 << 28) | (((u16)(sdram->mc_emem_arb_timing_ccdmw) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ddll_long_cmd_0 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_0 & 0x7FF | (pmc->scratch167 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch168 = (sdram->emc_pmacro_tx_sel_clk_src3 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 11 >> 31 << 28) | ((sdram->mc_emem_arb_override << 28 >> 31 << 27) | (((sdram->mc_emem_arb_override << 21 >> 31 << 25) | ((sdram->mc_emem_arb_override << 15 >> 31 << 24) | ((32 * sdram->mc_emem_arb_override >> 31 << 23) | ((16 * sdram->mc_emem_arb_override >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_1 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_1 & 0x7FF | (pmc->scratch168 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF | (sdram->mc_emem_arb_override << 27 >> 31 << 26)) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch169 = ((u16)(sdram->emc_rext) << 27) | (((u16)(sdram->emc_rrd) << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_2 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_2 & 0x7FF | (pmc->scratch169 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; -// pmc->scratch170 = ((u16)(sdram->emc_wext) << 27) | ((sdram->emc_tclkstop << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_3 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_3 & 0x7FF | (pmc->scratch170 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; -// tmp = (32 * sdram->emc_pmacro_perbit_fgcg_ctrl0 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl0 & 1 | 2 * (pmc->scratch171 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF; -// pmc->scratch171 = (sdram->emc_we_duration << 27) | ((sdram->emc_ref_ctrl2 >> 31 << 26) | ((32 * sdram->emc_ref_ctrl2 >> 29 << 23) | ((sdram->emc_ref_ctrl2 << 22) & 0x7FFFFF | tmp & 0xFFBFFFFF) & 0xFC7FFFFF) & 0xFBFFFFFF) & 0x7FFFFFF; -// tmp = (sdram->emc_pmacro_pad_cfg_ctrl << 22 >> 31 << 28) | ((sdram->emc_pmacro_pad_cfg_ctrl << 27) & 0xFFFFFFF | ((sdram->emc_ws_duration << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl1 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl1 & 1 | 2 * (pmc->scratch172 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; -// pmc->scratch172 = (sdram->emc_pmacro_pad_cfg_ctrl << 14 >> 30 << 30) | (4 * ((sdram->emc_pmacro_pad_cfg_ctrl << 18 >> 31 << 29) | tmp & 0xDFFFFFFF) >> 2); -// pmc->scratch173 = ((u8)(sdram->mc_emem_arb_timing_r2r) << 27) | ((sdram->mc_emem_arb_timing_rrd << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl2 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl2 & 1 | 2 * (pmc->scratch173 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0x7FFFFFF; -// tmp = 32 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl3 & 1 | 2 * (pmc->scratch174 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; -// pmc->scratch174 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30 >> 31 << 31) | (2 * (((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30) | ((32 * sdram->emc_pmacro_tx_sel_clk_src3 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 6 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 7 >> 31 << 27) | (((u8)(sdram->mc_emem_arb_timing_w2w) << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl3 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 25 >> 31 << 6) | tmp & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 28 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 29 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl4 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl4 & 1 | 2 * (pmc->scratch175 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF; -// pmc->scratch175 = (sdram->emc_pmacro_tx_sel_clk_src2 << 15 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 21 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 22 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 23 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 24 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 25 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 26 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 27 >> 31 << 24) | tmp & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 12 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 13 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 14 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl5 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl5 & 1 | 2 * (pmc->scratch176 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; -// pmc->scratch176 = (32 * sdram->emc_pmacro_tx_sel_clk_src2 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 6 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 8 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 9 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 10 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 11 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch177 = (sdram->emc_pmacro_tx_sel_clk_src4 << 22 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 23 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 24 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 25 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 26 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 27 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 28 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 29 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 30 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 22) & 0x7FFFFF | ((sdram->mc_emem_arb_cfg >> 28 << 18) | ((16 * sdram->mc_emem_arb_cfg >> 28 << 14) | ((sdram->mc_emem_arb_cfg << 11 >> 27 << 9) | (sdram->mc_emem_arb_cfg & 0x1FF | (pmc->scratch177 >> 9 << 9)) & 0xFFFFC1FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch178 = (sdram->emc_pmacro_tx_sel_clk_src4 << 7 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 8 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 9 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 10 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 11 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 12 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 13 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 14 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 15 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 21 >> 31 << 22) | ((sdram->mc_emem_arb_misc1 >> 28 << 18) | ((sdram->mc_emem_arb_misc1 << 6 >> 30 << 16) | ((sdram->mc_emem_arb_misc1 << 8 >> 29 << 13) | (16 * (sdram->mc_emem_arb_misc1 << 19 >> 23) | (8 * (sdram->mc_emem_arb_misc1 << 28 >> 31) | (4 * (sdram->mc_emem_arb_misc1 << 29 >> 31) | (2 * (sdram->mc_emem_arb_misc1 << 30 >> 31) | (sdram->mc_emem_arb_misc1 & 1 | 2 * (pmc->scratch178 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFE00F) & 0xFFFF1FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch179 = (sdram->emc_odt_write >> 31 << 31) | (2 * ((sdram->emc_odt_write << 20 >> 28 << 27) | ((sdram->emc_odt_write << 26 >> 31 << 26) | ((sdram->emc_odt_write << 27 >> 31 << 25) | ((sdram->emc_odt_write << 21) & 0x1FFFFFF | ((32 * sdram->emc_mrs_wait_cnt2 >> 21 << 10) | (sdram->emc_mrs_wait_cnt2 & 0x3FF | (pmc->scratch179 >> 10 << 10)) & 0xFFE003FF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); -// pmc->scratch180 = (sdram->emc_pmacro_ib_rxrt << 21) | ((32 * sdram->emc_mrs_wait_cnt >> 21 << 10) | (sdram->emc_mrs_wait_cnt & 0x3FF | (pmc->scratch180 >> 10 << 10)) & 0xFFE003FF) & 0x1FFFFF; -// pmc->scratch181 = ((u16)(sdram->emc_pmacro_ddll_long_cmd_4) << 21) | sdram->emc_auto_cal_interval & 0x1FFFFF; -// pmc->scratch182 = (sdram->mc_emem_arb_outstanding_req >> 31 << 31) | (2 * ((2 * sdram->mc_emem_arb_outstanding_req >> 31 << 30) | ((sdram->mc_emem_arb_outstanding_req << 23 >> 2) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 9 >> 25 << 14) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 17 >> 25 << 7) | (sdram->emc_emem_arb_refpb_hp_ctrl & 0x7F | (pmc->scratch182 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xC01FFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch183 = (4 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl0 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl0 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl0 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl0 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl0 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl0 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl0 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl0 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl0 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl0 << 20) & 0x1FFFFF | ((4 * sdram->emc_xm2_comp_pad_ctrl2 >> 26 << 14) | ((sdram->emc_xm2_comp_pad_ctrl2 << 10 >> 30 << 12) | ((sdram->emc_xm2_comp_pad_ctrl2 << 14 >> 31 << 11) | ((sdram->emc_xm2_comp_pad_ctrl2 << 15 >> 31 << 10) | ((sdram->emc_xm2_comp_pad_ctrl2 << 16 >> 30 << 8) | ((sdram->emc_xm2_comp_pad_ctrl2 << 18 >> 30 << 6) | (4 * (sdram->emc_xm2_comp_pad_ctrl2 << 26 >> 28) | (sdram->emc_xm2_comp_pad_ctrl2 & 3 | 4 * (pmc->scratch183 >> 2)) & 0xFFFFFFC3) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFF03FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch184 = (4 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl1 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl1 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl1 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl1 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl1 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl1 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl1 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl1 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl1 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl1 << 20) & 0x1FFFFF | ((sdram->emc_cfg_dig_dll_1 << 12 >> 28 << 16) | ((sdram->emc_cfg_dig_dll_1 << 16 >> 28 << 12) | ((sdram->emc_cfg_dig_dll_1 << 20 >> 26 << 6) | (2 * (sdram->emc_cfg_dig_dll_1 << 26 >> 27) | (sdram->emc_cfg_dig_dll_1 & 1 | 2 * (pmc->scratch184 >> 1)) & 0xFFFFFFC1) & 0xFFFFF03F) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch185 = (4 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl2 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl2 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl2 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl2 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl2 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl2 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl2 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl2 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl2 << 20) & 0x1FFFFF | ((sdram->emc_quse_brlshft0 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft0 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft0 << 22 >> 27) | (sdram->emc_quse_brlshft0 & 0x1F | 32 * (pmc->scratch185 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch186 = (sdram->emc_pmacro_dsr_vttgen_ctrl0 >> 8 << 24) | ((sdram->emc_pmacro_dsr_vttgen_ctrl0 << 20) | ((sdram->emc_quse_brlshft1 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft1 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft1 << 22 >> 27) | (sdram->emc_quse_brlshft1 & 0x1F | 32 * (pmc->scratch186 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFF0FFFFF) & 0xFFFFFF; -// pmc->scratch187 = (sdram->emc_pmacro_perbit_rfu1_ctrl0 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft2 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft2 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft2 << 22 >> 27) | (sdram->emc_quse_brlshft2 & 0x1F | 32 * (pmc->scratch187 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch188 = (sdram->emc_pmacro_perbit_rfu1_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft3 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft3 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft3 << 22 >> 27) | (sdram->emc_quse_brlshft3 & 0x1F | 32 * (pmc->scratch188 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); -// pmc->scratch189 = (sdram->emc_trefbw << 18) | ((sdram->emc_dbg >> 31 << 17) | ((2 * sdram->emc_dbg >> 31 << 16) | ((4 * sdram->emc_dbg >> 31 << 15) | ((8 * sdram->emc_dbg >> 31 << 14) | ((16 * sdram->emc_dbg >> 30 << 12) | ((sdram->emc_dbg << 6 >> 31 << 11) | ((sdram->emc_dbg << 7 >> 31 << 10) | ((sdram->emc_dbg << 18 >> 31 << 9) | ((sdram->emc_dbg << 19 >> 31 << 8) | ((sdram->emc_dbg << 20 >> 31 << 7) | ((sdram->emc_dbg << 21 >> 31 << 6) | (32 * (sdram->emc_dbg << 22 >> 31) | (16 * (sdram->emc_dbg << 27 >> 31) | (8 * (sdram->emc_dbg << 28 >> 31) | (4 * (sdram->emc_dbg << 29 >> 31) | (2 * (sdram->emc_dbg << 30 >> 31) | (sdram->emc_dbg & 1 | 2 * (pmc->scratch189 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0x3FFFF; -// pmc->scratch191 = (sdram->emc_qpop << 9 >> 25 << 25) | ((sdram->emc_qpop << 18) | ((sdram->emc_zcal_wait_cnt >> 31 << 17) | ((sdram->emc_zcal_wait_cnt << 10 >> 26 << 11) | (sdram->emc_zcal_wait_cnt & 0x7FF | (pmc->scratch191 >> 11 << 11)) & 0xFFFE07FF) & 0xFFFDFFFF) & 0xFE03FFFF) & 0x1FFFFFF; -// pmc->scratch192 = (sdram->emc_pmacro_tx_sel_clk_src4 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_auto_cal_common << 15 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_common << 18 >> 26 << 24) | ((sdram->emc_pmacro_auto_cal_common << 18) & 0xFFFFFF | ((sdram->emc_zcal_mrw_cmd >> 30 << 16) | ((sdram->emc_zcal_mrw_cmd << 8 >> 24 << 8) | (sdram->emc_zcal_mrw_cmd & 0xFF | (pmc->scratch192 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFCFFFF) & 0xFF03FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); -// tmp = (sdram->emc_dll_cfg1 << 7 >> 31 << 17) | ((sdram->emc_dll_cfg1 << 10 >> 31 << 16) | ((sdram->emc_dll_cfg1 << 11 >> 31 << 15) | ((sdram->emc_dll_cfg1 << 14 >> 30 << 13) | ((sdram->emc_dll_cfg1 << 18 >> 31 << 12) | ((sdram->emc_dll_cfg1 << 19 >> 31 << 11) | ((pmc->scratch193 >> 11 << 11) | sdram->emc_dll_cfg1 & 0x7FF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFF9FFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF; -// pmc->scratch193 = (sdram->emc_pmacro_tx_sel_clk_src5 << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src4 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 18) & 0xFFFFF | tmp & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl2 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch194 = (sdram->emc_pmacro_tx_sel_clk_src5 << 29 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 30 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 14 >> 30 << 24) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 18) & 0xFFFFF | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_cmd_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch194 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 26 >> 30 << 22)) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch195 = (sdram->emc_pmacro_tx_sel_clk_src5 << 27 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 28 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 18) & 0xFFFFF | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_data_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch195 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl4 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch196 = (sdram->emc_emem_arb_refpb_bank_ctrl >> 31 << 31) | (2 * ((sdram->emc_emem_arb_refpb_bank_ctrl << 17 >> 25 << 24) | ((sdram->emc_emem_arb_refpb_bank_ctrl << 17) & 0xFFFFFF | ((sdram->emc_dyn_self_ref_control >> 31 << 16) | (sdram->emc_dyn_self_ref_control & 0xFFFF | (pmc->scratch196 >> 16 << 16)) & 0xFFFEFFFF) & 0xFF01FFFF) & 0x80FFFFFF) >> 1); -// pmc->scratch197 = (sdram->emc_pmacro_tx_sel_clk_src5 << 24 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 25 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 26 >> 31 << 29) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 10 >> 30 << 27) | (((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 14 >> 30 << 23) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 26 >> 30 << 21) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 28 >> 30 << 19) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 17) & 0x7FFFF | ((16 * sdram->emc_pmacro_cmd_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_cmd_pad_rx_ctrl & 3 | 4 * (pmc->scratch197 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFF9FFFF) & 0xFFE7FFFF) & 0xFF9FFFFF) & 0xFE7FFFFF) & 0xF9FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl5 << 12 >> 30 << 25)) & 0xE7FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch198 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src5 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 7 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 8 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 9 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 10 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 11 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 12 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 13 >> 31 << 22) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 14 >> 31 << 21) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 15 >> 31 << 20) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 21 >> 31 << 19) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 22 >> 31 << 18) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 23 >> 31 << 17) | ((16 * sdram->emc_pmacro_data_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_data_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_data_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_data_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_data_pad_rx_ctrl & 3 | 4 * (pmc->scratch198 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch199 = (8 * sdram->emc_cmd_q >> 27 << 27) | ((sdram->emc_cmd_q << 17 >> 29 << 24) | ((sdram->emc_cmd_q << 21 >> 29 << 21) | ((sdram->emc_cmd_q << 16) & 0x1FFFFF | (((u16)(sdram->emc_refresh) << 16 >> 22 << 6) | (sdram->emc_refresh & 0x3F | (pmc->scratch199 >> 6 << 6)) & 0xFFFF003F) & 0xFFE0FFFF) & 0xFF1FFFFF) & 0xF8FFFFFF) & 0x7FFFFFF; -// pmc->scratch210 = (sdram->emc_auto_cal_vref_sel1 << 16 >> 31 << 31) | (2 * ((sdram->emc_auto_cal_vref_sel1 << 17 >> 25 << 24) | ((sdram->emc_auto_cal_vref_sel1 << 24 >> 31 << 23) | ((sdram->emc_auto_cal_vref_sel1 << 16) & 0x7FFFFF | (sdram->emc_acpd_control & 0xFFFF | (pmc->scratch210 >> 16 << 16)) & 0xFF80FFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); -// tmp = 8 * (sdram->emc_pmacro_auto_cal_cfg0 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg0 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg0 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg0 & 1 | 2 * (pmc->scratch211 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7; -// tmp = (sdram->emc_pmacro_auto_cal_cfg1 << 7 >> 31 << 28) | ((sdram->emc_pmacro_auto_cal_cfg1 << 12 >> 31 << 27) | ((sdram->emc_pmacro_auto_cal_cfg1 << 13 >> 31 << 26) | ((sdram->emc_pmacro_auto_cal_cfg1 << 14 >> 31 << 25) | ((sdram->emc_pmacro_auto_cal_cfg1 << 15 >> 31 << 24) | ((sdram->emc_pmacro_auto_cal_cfg1 << 20 >> 31 << 23) | ((sdram->emc_pmacro_auto_cal_cfg1 << 21 >> 31 << 22) | ((sdram->emc_pmacro_auto_cal_cfg1 << 22 >> 31 << 21) | ((sdram->emc_pmacro_auto_cal_cfg1 << 23 >> 31 << 20) | ((sdram->emc_pmacro_auto_cal_cfg1 << 28 >> 31 << 19) | ((sdram->emc_pmacro_auto_cal_cfg1 << 29 >> 31 << 18) | ((sdram->emc_pmacro_auto_cal_cfg1 << 30 >> 31 << 17) | ((sdram->emc_pmacro_auto_cal_cfg1 << 16) & 0x1FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg0 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg0 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg0 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg0 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg0 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg0 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg0 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg0 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg0 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg0 << 23 >> 31) | tmp & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; -// pmc->scratch211 = (16 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 31) | (2 * ((32 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_cfg1 << 6 >> 31 << 29) | tmp & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->scratch212 = (sdram->emc_xm2_comp_pad_ctrl3 << 8 >> 28 << 28) | ((sdram->emc_xm2_comp_pad_ctrl3 << 14 >> 31 << 27) | ((sdram->emc_xm2_comp_pad_ctrl3 << 15 >> 31 << 26) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16 >> 30 << 24) | ((sdram->emc_xm2_comp_pad_ctrl3 << 18 >> 30 << 22) | ((sdram->emc_xm2_comp_pad_ctrl3 << 26 >> 28 << 18) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16) & 0x3FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg2 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg2 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg2 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg2 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg2 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg2 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg2 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg2 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg2 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg2 << 23 >> 31) | (8 * (sdram->emc_pmacro_auto_cal_cfg2 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg2 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg2 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg2 & 1 | 2 * (pmc->scratch212 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; -// pmc->scratch213 = ((u16)(sdram->emc_prerefresh_req_cnt) << 16) | (u16)(sdram->emc_cfg_dig_dll_period); -// pmc->scratch214 = (sdram->emc_pmacro_data_pi_ctrl << 10 >> 26 << 26) | ((sdram->emc_pmacro_data_pi_ctrl << 19 >> 31 << 25) | ((sdram->emc_pmacro_data_pi_ctrl << 20 >> 28 << 21) | ((sdram->emc_pmacro_data_pi_ctrl << 27 >> 31 << 20) | ((sdram->emc_pmacro_data_pi_ctrl << 16) & 0xFFFFF | ((sdram->emc_pmacro_ddll_bypass >> 31 << 15) | ((2 * sdram->emc_pmacro_ddll_bypass >> 31 << 14) | ((4 * sdram->emc_pmacro_ddll_bypass >> 31 << 13) | ((16 * sdram->emc_pmacro_ddll_bypass >> 31 << 12) | ((32 * sdram->emc_pmacro_ddll_bypass >> 31 << 11) | ((sdram->emc_pmacro_ddll_bypass << 6 >> 31 << 10) | ((sdram->emc_pmacro_ddll_bypass << 7 >> 31 << 9) | ((sdram->emc_pmacro_ddll_bypass << 15 >> 31 << 8) | ((sdram->emc_pmacro_ddll_bypass << 16 >> 31 << 7) | ((sdram->emc_pmacro_ddll_bypass << 17 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_bypass << 18 >> 31) | (16 * (sdram->emc_pmacro_ddll_bypass << 20 >> 31) | (8 * (sdram->emc_pmacro_ddll_bypass << 21 >> 31) | (4 * (sdram->emc_pmacro_ddll_bypass << 22 >> 31) | (2 * (sdram->emc_pmacro_ddll_bypass << 23 >> 31) | (sdram->emc_pmacro_ddll_bypass & 1 | 2 * (pmc->scratch214 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; -// pmc->scratch215 = (sdram->emc_pmacro_cmd_pi_ctrl << 10 >> 26 << 10) | ((sdram->emc_pmacro_cmd_pi_ctrl << 19 >> 31 << 9) | (32 * (sdram->emc_pmacro_cmd_pi_ctrl << 20 >> 28) | (16 * (sdram->emc_pmacro_cmd_pi_ctrl << 27 >> 31) | (sdram->emc_pmacro_cmd_pi_ctrl & 0xF | 16 * (pmc->scratch215 >> 4)) & 0xFFFFFFEF) & 0xFFFFFE1F) & 0xFFFFFDFF) & 0xFFFF03FF; -// tmp = (sdram->emc_pmacro_data_pad_tx_ctrl << 7 >> 31 << 24) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 8 >> 31 << 23) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 9 >> 31 << 22) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 10 >> 31 << 21) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15 >> 31 << 20) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 16 >> 31 << 19) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 21 >> 31 << 18) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 25 >> 31 << 17) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 26 >> 31 << 16) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15) & 0xFFFF | ((2 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 14) | ((4 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 13) | ((8 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 12) | ((16 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 11) | ((32 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 6 >> 31 << 9) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 7 >> 31 << 8) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 8 >> 31 << 7) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 9 >> 31 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 10 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 15 >> 31) | (8 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 16 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 21 >> 31) | (2 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 25 >> 31) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 26 >> 31) | 2 * (pmc->scratch216 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; + s(emc_pin_gpio, 1:0, scratch9, 31:30); + s(emc_pin_gpio_enable, 1:0, scratch10, 31:30); + s(emc_dev_select, 1:0, scratch11, 31:30); + s(emc_zcal_warm_cold_boot_enables, 1:0, scratch12, 31:30); + s(emc_cfg_dig_dll_period_warm_boot, 1:0, scratch13, 31:30); + s32(emc_bct_spare13, scratch45); + s32(emc_bct_spare12, scratch46); + s32(emc_bct_spare7, scratch47); + s32(emc_bct_spare6, scratch48); + s32(emc_bct_spare5, scratch50); + s32(emc_bct_spare4, scratch51); + s32(emc_bct_spare3, scratch56); + s32(emc_bct_spare2, scratch57); + s32(emc_bct_spare1, scratch58); + s32(emc_bct_spare0, scratch59); + s32(emc_bct_spare9, scratch60); + s32(emc_bct_spare8, scratch61); + s32(boot_rom_patch_data, scratch62); + s32(boot_rom_patch_control, scratch63); + s(mc_clken_override_allwarm_boot, 0:0, scratch65, 31:31); + pmc->scratch66 = pmc->scratch66 & 0x1FFFFFFF | ((u8)(sdram->emc_extra_refresh_num) << 29); + pmc->scratch72 = pmc->scratch72 & 0x8FFFFFFF | ((u16)(sdram->pmc_io_dpd3_req_wait) << 28) & 0x70000000; + pmc->scratch72 = ((2 * pmc->scratch72) >> 1) | ((u16)(sdram->emc_clken_override_allwarm_boot) << 31); + pmc->scratch73 = pmc->scratch73 & 0x8FFFFFFF | ((u8)(sdram->memory_type) << 28) & 0x70000000; + pmc->scratch73 = ((2 * pmc->scratch73) >> 1) | (sdram->emc_mrs_warm_boot_enable << 31); + pmc->scratch74 = pmc->scratch74 & 0x8FFFFFFF | (sdram->pmc_io_dpd4_req_wait << 28) & 0x70000000; + pmc->scratch74 = ((2 * pmc->scratch74) >> 1) | (sdram->clear_clock2_mc1 << 31); + pmc->scratch75 = pmc->scratch75 & 0xEFFFFFFF | (sdram->emc_warm_boot_extramode_reg_write_enable << 28) & 0x10000000; + pmc->scratch75 = pmc->scratch75 & 0xDFFFFFFF | (sdram->clk_rst_pllm_misc20_override_enable << 29) & 0x20000000; + pmc->scratch75 = pmc->scratch75 & 0xBFFFFFFF | ((u16)(sdram->emc_dbg_write_mux) << 30) & 0x40000000; + pmc->scratch75 = ((2 * pmc->scratch75) >> 1) | ((u16)(sdram->ahb_arbitration_xbar_ctrl_meminit_done) << 31); + pmc->scratch90 = pmc->scratch90 & 0xFFFFFF | (sdram->emc_timing_control_wait << 24); + pmc->scratch91 = pmc->scratch91 & 0xFFFFFF | (sdram->emc_zcal_warm_boot_wait << 24); + pmc->scratch92 = pmc->scratch92 & 0xFFFFFF | (sdram->warm_boot_wait << 24); + pmc->scratch93 = pmc->scratch93 & 0xFFFFFF | ((u16)(sdram->emc_pin_program_wait) << 24); + pmc->scratch114 = pmc->scratch114 & 0x3FFFFF | ((u16)(sdram->emc_auto_cal_wait) << 22); + pmc->scratch215 = (u16)pmc->scratch215 | ((u16)(sdram->swizzle_rank_byte_encode) << 16); + pmc->scratch216 = (2 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 30) | ((4 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 29) | ((8 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 28) | ((16 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 27) | ((32 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 26) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 6 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF; + s(emc_mrw_lpddr2zcal_warm_boot, 23:16, scratch5, 7:0); + s(emc_mrw_lpddr2zcal_warm_boot, 7:0, scratch5, 15:8); + s(emc_warm_boot_mrw_extra, 23:16, scratch5, 23:16); + s(emc_warm_boot_mrw_extra, 7:0, scratch5, 31:24); + s(emc_mrw_lpddr2zcal_warm_boot, 31:30, scratch6, 1:0); + s(emc_warm_boot_mrw_extra, 31:30, scratch6, 3:2); + s(emc_mrw_lpddr2zcal_warm_boot, 27:26, scratch6, 5:4); + s(emc_warm_boot_mrw_extra, 27:26, scratch6, 7:6); + s(emc_mrw6, 27:0, scratch8, 27:0); + s(emc_mrw6, 31:30, scratch8, 29:28); + s(emc_mrw8, 27:0, scratch9, 27:0); + s(emc_mrw8, 31:30, scratch9, 29:28); + s(emc_mrw9, 27:0, scratch10, 27:0); + s(emc_mrw9, 31:30, scratch10, 29:28); + s(emc_mrw10, 27:0, scratch11, 27:0); + s(emc_mrw10, 31:30, scratch11, 29:28); + s(emc_mrw12, 27:0, scratch12, 27:0); + s(emc_mrw12, 31:30, scratch12, 29:28); + s(emc_mrw13, 27:0, scratch13, 27:0); + s(emc_mrw13, 31:30, scratch13, 29:28); + s(emc_mrw14, 27:0, scratch14, 27:0); + s(emc_mrw14, 31:30, scratch14, 29:28); + s(emc_mrw1, 7:0, scratch15, 7:0); + s(emc_mrw1, 23:16, scratch15, 15:8); + s(emc_mrw1, 27:26, scratch15, 17:16); + s(emc_mrw1, 31:30, scratch15, 19:18); + s(emc_warm_boot_mrw_extra, 7:0, scratch16, 7:0); + s(emc_warm_boot_mrw_extra, 23:16, scratch16, 15:8); + s(emc_warm_boot_mrw_extra, 27:26, scratch16, 17:16); + s(emc_warm_boot_mrw_extra, 31:30, scratch16, 19:18); + s(emc_mrw2, 7:0, scratch17, 7:0); + s(emc_mrw2, 23:16, scratch17, 15:8); + s(emc_mrw2, 27:26, scratch17, 17:16); + s(emc_mrw2, 31:30, scratch17, 19:18); + pmc->scratch18 = (sdram->emc_mrw3 >> 30 << 18) | ((16 * sdram->emc_mrw3 >> 31 << 17) | ((32 * sdram->emc_mrw3 >> 31 << 16) | ((sdram->emc_mrw3 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw3 | (pmc->scratch18 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->scratch19 = (sdram->emc_mrw4 >> 30 << 18) | ((16 * sdram->emc_mrw4 >> 31 << 17) | ((32 * sdram->emc_mrw4 >> 31 << 16) | ((sdram->emc_mrw4 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw4 | (pmc->scratch19 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + s32(emc_cmd_mapping_byte, secure_scratch8); + s32(emc_pmacro_brick_mapping0, secure_scratch9); + s32(emc_pmacro_brick_mapping1, secure_scratch10); + s32(emc_pmacro_brick_mapping2, secure_scratch11); + s32(mc_video_protect_gpu_override0, secure_scratch12); + pmc->secure_scratch13 = ((u16)(sdram->emc_adr_cfg) << 31) | (2 * ((((u16)(sdram->mc_untranslated_region_check) << 22) >> 31 << 30) | ((((u16)(sdram->mc_untranslated_region_check) << 23) >> 31 << 29) | (((u16)(sdram->mc_untranslated_region_check) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd0_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_0 & 0x7F | (pmc->secure_scratch13 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch14 = (sdram->mc_video_protect_write_access << 30 >> 31 << 31) | (2 * ((sdram->mc_video_protect_write_access << 30) | ((sdram->mc_video_protect_bom_adr_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd0_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_1 & 0x7F | (pmc->secure_scratch14 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch15 = ((u16)(sdram->mc_mts_carveout_adr_hi) << 30) | (4 * ((sdram->mc_sec_carveout_adr_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_0 & 0x7F | (pmc->secure_scratch15 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch16 = (sdram->mc_generalized_carveout3_bom_hi << 30) | (4 * ((sdram->mc_generalized_carveout5_bom_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_1 & 0x7F | (pmc->secure_scratch16 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch17 = ((u16)(sdram->mc_generalized_carveout4_bom_hi) << 30) | (4 * (((u16)(sdram->mc_generalized_carveout2_bom_hi) << 28) | ((2 * sdram->emc_cmd_mapping_cmd2_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_0 & 0x7F | (pmc->secure_scratch17 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch18 = (sdram->emc_fbio_cfg8 << 16 >> 31 << 31) | (2 * (((u16)(sdram->emc_fbio_spare) << 30 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd2_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_1 & 0x7F | (pmc->secure_scratch18 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch19 = (sdram->mc_video_protect_vpr_override << 31) | (2 * (((u16)(sdram->mc_mts_carveout_reg_ctrl) << 30) | ((sdram->mc_sec_carveout_protect_write_access << 31 >> 2) | (((u16)(sdram->mc_emem_adr_cfg) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd3_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_0 & 0x7F | (pmc->secure_scratch19 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch20 = (sdram->mc_generalized_carveout2_cfg0 << 25 >> 28 << 28) | ((2 * sdram->emc_cmd_mapping_cmd3_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_1 & 0x7F | (pmc->secure_scratch20 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->secure_scratch39 = (sdram->mc_video_protect_vpr_override << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 21 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout4_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout4_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout4_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout4_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout4_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout4_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout4_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout4_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout4_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout4_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout4_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout4_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout4_cfg0 & 1 | 2 * (pmc->secure_scratch39 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch40 = (sdram->mc_video_protect_vpr_override << 29 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 14 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout5_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout5_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout5_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout5_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout5_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout5_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout5_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout5_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout5_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout5_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout5_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout5_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout5_cfg0 & 1 | 2 * (pmc->secure_scratch40 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch41 = (sdram->mc_generalized_carveout2_cfg0 << 18 >> 29 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 10 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd0_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd0_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_2 & 0x7F | (pmc->secure_scratch41 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch42 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 25 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd1_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd1_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_2 & 0x7F | (pmc->secure_scratch42 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch43 = ((u16)(sdram->mc_generalized_carveout3_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 21 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd2_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd2_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_2 & 0x7F | (pmc->secure_scratch43 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch44 = (sdram->mc_video_protect_vpr_override << 24 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 25 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override << 28 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 14 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd3_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd3_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_2 & 0x7F | (pmc->secure_scratch44 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + s(mc_emem_adr_cfg_channel_mask, 31:9, secure_scratch45, 22:0); + s(mc_emem_adr_cfg_dev0, 2:0, secure_scratch45, 25:23); + s(mc_emem_adr_cfg_dev0, 9:8, secure_scratch45, 27:26); + s(mc_emem_adr_cfg_dev0, 19:16, secure_scratch45, 31:28); + pmc->secure_scratch46 = (sdram->mc_video_protect_vpr_override << 23 >> 31 << 31) | (2 * ((sdram->mc_emem_adr_cfg_dev1 << 12 >> 28 << 27) | ((sdram->mc_emem_adr_cfg_dev1 << 22 >> 30 << 25) | ((sdram->mc_emem_adr_cfg_dev1 << 22) & 0x1FFFFFF | ((sdram->mc_emem_adr_cfg_bank_mask0 >> 10) | (pmc->secure_scratch46 >> 22 << 22)) & 0xFE3FFFFF) & 0xF9FFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch47 = (sdram->mc_video_protect_vpr_override << 20 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 22 >> 31 << 30) | (((u8)(sdram->mc_generalized_carveout3_cfg0) << 25 >> 28 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 10 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask1 >> 10) | (pmc->secure_scratch47 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch48 = (sdram->mc_video_protect_vpr_override << 16 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 17 >> 31 << 30) | ((sdram->mc_generalized_carveout3_cfg0 << 14 >> 28 << 26) | ((sdram->mc_generalized_carveout3_cfg0 << 21 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask2 >> 10) | (pmc->secure_scratch48 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch49 = (sdram->mc_video_protect_vpr_override << 14 >> 31 << 31) | (2 * ((sdram->mc_emem_cfg >> 31 << 30) | ((sdram->mc_emem_cfg << 18 >> 2) | (sdram->mc_video_protect_gpu_override1 & 0xFFFF | (pmc->secure_scratch49 >> 16 << 16)) & 0xC000FFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch50 = (sdram->mc_video_protect_vpr_override << 12 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 13 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom >> 17 << 15) | ((sdram->mc_generalized_carveout3_bom >> 17) | (pmc->secure_scratch50 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch51 = (sdram->mc_video_protect_vpr_override << 10 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 11 >> 31 << 30) | ((sdram->mc_generalized_carveout2_bom >> 17 << 15) | ((sdram->mc_generalized_carveout4_bom >> 17) | (pmc->secure_scratch51 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch52 = (sdram->mc_video_protect_vpr_override << 9 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout3_cfg0 << 10 >> 28 << 27) | ((sdram->mc_video_protect_bom >> 20 << 15) | ((sdram->mc_generalized_carveout5_bom >> 17) | (pmc->secure_scratch52 >> 15 << 15)) & 0xF8007FFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch53 = (sdram->mc_video_protect_vpr_override1 << 27 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 30 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 31 >> 2) | ((sdram->mc_video_protect_vpr_override >> 31 << 28) | ((2 * sdram->mc_video_protect_vpr_override >> 31 << 27) | ((4 * sdram->mc_video_protect_vpr_override >> 31 << 26) | ((32 * sdram->mc_video_protect_vpr_override >> 31 << 25) | ((sdram->mc_video_protect_vpr_override << 8 >> 31 << 24) | ((sdram->mc_sec_carveout_bom >> 20 << 12) | (sdram->mc_video_protect_size_mb & 0xFFF | (pmc->secure_scratch53 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch54 = (sdram->mc_video_protect_vpr_override1 << 19 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 20 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 21 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 22 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 23 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 24 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 25 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 26 >> 31 << 24) | ((sdram->mc_mts_carveout_bom >> 20 << 12) | (sdram->mc_sec_carveout_size_mb & 0xFFF | (pmc->secure_scratch54 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch55 = (sdram->mc_generalized_carveout2_cfg0 << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 30) | ((32 * sdram->mc_video_protect_vpr_override1 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 6 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 15 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 16 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 17 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 18 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout4_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_mts_carveout_size_mb & 0xFFF | (pmc->secure_scratch55 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch56 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 30 >> 31 << 31) | (2 * (((u16)(sdram->mc_generalized_carveout1_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout2_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout2_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout2_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout2_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout2_cfg0 << 29 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout2_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout3_size_128kb & 0xFFF | (pmc->secure_scratch56 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch57 = ((u8)(sdram->mc_generalized_carveout3_cfg0) << 30 >> 31 << 31) | (2 * (((u8)(sdram->mc_generalized_carveout3_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout1_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout1_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout1_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout1_cfg0 << 29 >> 31 << 24) | ((sdram->mc_generalized_carveout5_size_128kb << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout1_size_128kb & 0xFFF | (pmc->secure_scratch57 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// s(emc_pin_gpio, 1:0, scratch9, 31:30); -// s(emc_pin_gpio_enable, 1:0, scratch10, 31:30); -// s(emc_dev_select, 1:0, scratch11, 31:30); -// s(emc_zcal_warm_cold_boot_enables, 1:0, scratch12, 31:30); -// s(emc_cfg_dig_dll_period_warm_boot, 1:0, scratch13, 31:30); -// s32(emc_bct_spare13, scratch45); -// s32(emc_bct_spare12, scratch46); -// s32(emc_bct_spare7, scratch47); -// s32(emc_bct_spare6, scratch48); -// s32(emc_bct_spare5, scratch50); -// s32(emc_bct_spare4, scratch51); -// s32(emc_bct_spare3, scratch56); -// s32(emc_bct_spare2, scratch57); -// s32(emc_bct_spare1, scratch58); -// s32(emc_bct_spare0, scratch59); -// s32(emc_bct_spare9, scratch60); -// s32(emc_bct_spare8, scratch61); -// s32(boot_rom_patch_data, scratch62); -// s32(boot_rom_patch_control, scratch63); -// s(mc_clken_override_allwarm_boot, 0:0, scratch65, 31:31); -// pmc->scratch66 = pmc->scratch66 & 0x1FFFFFFF | ((u8)(sdram->emc_extra_refresh_num) << 29); -// pmc->scratch72 = pmc->scratch72 & 0x8FFFFFFF | ((u16)(sdram->pmc_io_dpd3_req_wait) << 28) & 0x70000000; -// pmc->scratch72 = ((2 * pmc->scratch72) >> 1) | ((u16)(sdram->emc_clken_override_allwarm_boot) << 31); -// pmc->scratch73 = pmc->scratch73 & 0x8FFFFFFF | ((u8)(sdram->memory_type) << 28) & 0x70000000; -// pmc->scratch73 = ((2 * pmc->scratch73) >> 1) | (sdram->emc_mrs_warm_boot_enable << 31); -// pmc->scratch74 = pmc->scratch74 & 0x8FFFFFFF | (sdram->pmc_io_dpd4_req_wait << 28) & 0x70000000; -// pmc->scratch74 = ((2 * pmc->scratch74) >> 1) | (sdram->clear_clock2_mc1 << 31); -// pmc->scratch75 = pmc->scratch75 & 0xEFFFFFFF | (sdram->emc_warm_boot_extramode_reg_write_enable << 28) & 0x10000000; -// pmc->scratch75 = pmc->scratch75 & 0xDFFFFFFF | (sdram->clk_rst_pllm_misc20_override_enable << 29) & 0x20000000; -// pmc->scratch75 = pmc->scratch75 & 0xBFFFFFFF | ((u16)(sdram->emc_dbg_write_mux) << 30) & 0x40000000; -// pmc->scratch75 = ((2 * pmc->scratch75) >> 1) | ((u16)(sdram->ahb_arbitration_xbar_ctrl_meminit_done) << 31); -// pmc->scratch90 = pmc->scratch90 & 0xFFFFFF | (sdram->emc_timing_control_wait << 24); -// pmc->scratch91 = pmc->scratch91 & 0xFFFFFF | (sdram->emc_zcal_warm_boot_wait << 24); -// pmc->scratch92 = pmc->scratch92 & 0xFFFFFF | (sdram->warm_boot_wait << 24); -// pmc->scratch93 = pmc->scratch93 & 0xFFFFFF | ((u16)(sdram->emc_pin_program_wait) << 24); -// pmc->scratch114 = pmc->scratch114 & 0x3FFFFF | ((u16)(sdram->emc_auto_cal_wait) << 22); -// pmc->scratch215 = (u16)pmc->scratch215 | ((u16)(sdram->swizzle_rank_byte_encode) << 16); -// pmc->scratch216 = (2 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 30) | ((4 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 29) | ((8 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 28) | ((16 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 27) | ((32 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 26) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 6 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF; -// s(emc_mrw_lpddr2zcal_warm_boot, 23:16, scratch5, 7:0); -// s(emc_mrw_lpddr2zcal_warm_boot, 7:0, scratch5, 15:8); -// s(emc_warm_boot_mrw_extra, 23:16, scratch5, 23:16); -// s(emc_warm_boot_mrw_extra, 7:0, scratch5, 31:24); -// s(emc_mrw_lpddr2zcal_warm_boot, 31:30, scratch6, 1:0); -// s(emc_warm_boot_mrw_extra, 31:30, scratch6, 3:2); -// s(emc_mrw_lpddr2zcal_warm_boot, 27:26, scratch6, 5:4); -// s(emc_warm_boot_mrw_extra, 27:26, scratch6, 7:6); -// s(EmcMrw6, 27:0, scratch8, 27:0); -// s(EmcMrw6, 31:30, scratch8, 29:28); -// s(EmcMrw8, 27:0, scratch9, 27:0); -// s(EmcMrw8, 31:30, scratch9, 29:28); -// s(EmcMrw9, 27:0, scratch10, 27:0); -// s(EmcMrw9, 31:30, scratch10, 29:28); -// s(EmcMrw10, 27:0, scratch11, 27:0); -// s(EmcMrw10, 31:30, scratch11, 29:28); -// s(EmcMrw12, 27:0, scratch12, 27:0); -// s(EmcMrw12, 31:30, scratch12, 29:28); -// s(EmcMrw13, 27:0, scratch13, 27:0); -// s(EmcMrw13, 31:30, scratch13, 29:28); -// s(EmcMrw14, 27:0, scratch14, 27:0); -// s(EmcMrw14, 31:30, scratch14, 29:28); -// s(EmcMrw1, 7:0, scratch15, 7:0); -// s(EmcMrw1, 23:16, scratch15, 15:8); -// s(EmcMrw1, 27:26, scratch15, 17:16); -// s(EmcMrw1, 31:30, scratch15, 19:18); -// s(emc_warm_boot_mrw_extra, 7:0, scratch16, 7:0); -// s(emc_warm_boot_mrw_extra, 23:16, scratch16, 15:8); -// s(emc_warm_boot_mrw_extra, 27:26, scratch16, 17:16); -// s(emc_warm_boot_mrw_extra, 31:30, scratch16, 19:18); -// s(emc_mrw2, 7:0, scratch17, 7:0); -// s(emc_mrw2, 23:16, scratch17, 15:8); -// s(emc_mrw2, 27:26, scratch17, 17:16); -// s(emc_mrw2, 31:30, scratch17, 19:18); -// pmc->scratch18 = (sdram->emc_mrw3 >> 30 << 18) | ((16 * sdram->emc_mrw3 >> 31 << 17) | ((32 * sdram->emc_mrw3 >> 31 << 16) | ((sdram->emc_mrw3 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw3 | (pmc->scratch18 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; -// pmc->scratch19 = (sdram->emc_mrw4 >> 30 << 18) | ((16 * sdram->emc_mrw4 >> 31 << 17) | ((32 * sdram->emc_mrw4 >> 31 << 16) | ((sdram->emc_mrw4 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw4 | (pmc->scratch19 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; -// s32(emc_cmd_mapping_byte, secure_scratch8); -// s32(emc_pmacro_brick_mapping0, secure_scratch9); -// s32(emc_pmacro_brick_mapping1, secure_scratch10); -// s32(emc_pmacro_brick_mapping2, secure_scratch11); -// s32(mc_video_protect_gpu_override0, secure_scratch12); -// pmc->secure_scratch13 = ((u16)(sdram->emc_adr_cfg) << 31) | (2 * ((((u16)(sdram->mc_untranslated_region_check) << 22) >> 31 << 30) | ((((u16)(sdram->mc_untranslated_region_check) << 23) >> 31 << 29) | (((u16)(sdram->mc_untranslated_region_check) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd0_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_0 & 0x7F | (pmc->secure_scratch13 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch14 = (sdram->mc_video_protect_write_access << 30 >> 31 << 31) | (2 * ((sdram->mc_video_protect_write_access << 30) | ((sdram->mc_video_protect_bom_adr_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd0_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_1 & 0x7F | (pmc->secure_scratch14 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch15 = ((u16)(sdram->mc_mts_carveout_adr_hi) << 30) | (4 * ((sdram->mc_sec_carveout_adr_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_0 & 0x7F | (pmc->secure_scratch15 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); -// pmc->secure_scratch16 = (sdram->mc_generalized_carveout3_bom_hi << 30) | (4 * ((sdram->mc_generalized_carveout5_bom_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_1 & 0x7F | (pmc->secure_scratch16 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); -// pmc->secure_scratch17 = ((u16)(sdram->mc_generalized_carveout4_bom_hi) << 30) | (4 * (((u16)(sdram->mc_generalized_carveout2_bom_hi) << 28) | ((2 * sdram->emc_cmd_mapping_cmd2_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_0 & 0x7F | (pmc->secure_scratch17 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); -// pmc->secure_scratch18 = (sdram->emc_fbio_cfg8 << 16 >> 31 << 31) | (2 * (((u16)(sdram->emc_fbio_spare) << 30 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd2_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_1 & 0x7F | (pmc->secure_scratch18 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch19 = (sdram->mc_video_protect_vpr_override << 31) | (2 * (((u16)(sdram->mc_mts_carveout_reg_ctrl) << 30) | ((sdram->mc_sec_carveout_protect_write_access << 31 >> 2) | (((u16)(sdram->mc_emem_adr_cfg) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd3_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_0 & 0x7F | (pmc->secure_scratch19 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch20 = (sdram->mc_generalized_carveout2_cfg0 << 25 >> 28 << 28) | ((2 * sdram->emc_cmd_mapping_cmd3_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_1 & 0x7F | (pmc->secure_scratch20 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; -// pmc->secure_scratch39 = (sdram->mc_video_protect_vpr_override << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 21 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout4_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout4_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout4_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout4_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout4_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout4_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout4_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout4_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout4_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout4_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout4_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout4_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout4_cfg0 & 1 | 2 * (pmc->secure_scratch39 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); -// pmc->secure_scratch40 = (sdram->mc_video_protect_vpr_override << 29 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 14 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout5_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout5_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout5_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout5_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout5_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout5_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout5_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout5_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout5_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout5_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout5_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout5_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout5_cfg0 & 1 | 2 * (pmc->secure_scratch40 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); -// pmc->secure_scratch41 = (sdram->mc_generalized_carveout2_cfg0 << 18 >> 29 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 10 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd0_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd0_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_2 & 0x7F | (pmc->secure_scratch41 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; -// pmc->secure_scratch42 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 25 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd1_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd1_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_2 & 0x7F | (pmc->secure_scratch42 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; -// pmc->secure_scratch43 = ((u16)(sdram->mc_generalized_carveout3_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 21 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd2_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd2_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_2 & 0x7F | (pmc->secure_scratch43 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; -// pmc->secure_scratch44 = (sdram->mc_video_protect_vpr_override << 24 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 25 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override << 28 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 14 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd3_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd3_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_2 & 0x7F | (pmc->secure_scratch44 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// s(mc_emem_adr_cfg_channel_mask, 31:9, secure_scratch45, 22:0); -// s(mc_emem_adr_cfg_dev0, 2:0, secure_scratch45, 25:23); -// s(mc_emem_adr_cfg_dev0, 9:8, secure_scratch45, 27:26); -// s(mc_emem_adr_cfg_dev0, 19:16, secure_scratch45, 31:28); -// pmc->secure_scratch46 = (sdram->mc_video_protect_vpr_override << 23 >> 31 << 31) | (2 * ((sdram->mc_emem_adr_cfg_dev1 << 12 >> 28 << 27) | ((sdram->mc_emem_adr_cfg_dev1 << 22 >> 30 << 25) | ((sdram->mc_emem_adr_cfg_dev1 << 22) & 0x1FFFFFF | ((sdram->mc_emem_adr_cfg_bank_mask0 >> 10) | (pmc->secure_scratch46 >> 22 << 22)) & 0xFE3FFFFF) & 0xF9FFFFFF) & 0x87FFFFFF) >> 1); -// pmc->secure_scratch47 = (sdram->mc_video_protect_vpr_override << 20 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 22 >> 31 << 30) | (((u8)(sdram->mc_generalized_carveout3_cfg0) << 25 >> 28 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 10 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask1 >> 10) | (pmc->secure_scratch47 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch48 = (sdram->mc_video_protect_vpr_override << 16 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 17 >> 31 << 30) | ((sdram->mc_generalized_carveout3_cfg0 << 14 >> 28 << 26) | ((sdram->mc_generalized_carveout3_cfg0 << 21 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask2 >> 10) | (pmc->secure_scratch48 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch49 = (sdram->mc_video_protect_vpr_override << 14 >> 31 << 31) | (2 * ((sdram->mc_emem_cfg >> 31 << 30) | ((sdram->mc_emem_cfg << 18 >> 2) | (sdram->mc_video_protect_gpu_override1 & 0xFFFF | (pmc->secure_scratch49 >> 16 << 16)) & 0xC000FFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch50 = (sdram->mc_video_protect_vpr_override << 12 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 13 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom >> 17 << 15) | ((sdram->mc_generalized_carveout3_bom >> 17) | (pmc->secure_scratch50 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch51 = (sdram->mc_video_protect_vpr_override << 10 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 11 >> 31 << 30) | ((sdram->mc_generalized_carveout2_bom >> 17 << 15) | ((sdram->mc_generalized_carveout4_bom >> 17) | (pmc->secure_scratch51 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch52 = (sdram->mc_video_protect_vpr_override << 9 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout3_cfg0 << 10 >> 28 << 27) | ((sdram->mc_video_protect_bom >> 20 << 15) | ((sdram->mc_generalized_carveout5_bom >> 17) | (pmc->secure_scratch52 >> 15 << 15)) & 0xF8007FFF) & 0x87FFFFFF) >> 1); -// pmc->secure_scratch53 = (sdram->mc_video_protect_vpr_override1 << 27 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 30 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 31 >> 2) | ((sdram->mc_video_protect_vpr_override >> 31 << 28) | ((2 * sdram->mc_video_protect_vpr_override >> 31 << 27) | ((4 * sdram->mc_video_protect_vpr_override >> 31 << 26) | ((32 * sdram->mc_video_protect_vpr_override >> 31 << 25) | ((sdram->mc_video_protect_vpr_override << 8 >> 31 << 24) | ((sdram->mc_sec_carveout_bom >> 20 << 12) | (sdram->mc_video_protect_size_mb & 0xFFF | (pmc->secure_scratch53 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch54 = (sdram->mc_video_protect_vpr_override1 << 19 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 20 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 21 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 22 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 23 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 24 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 25 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 26 >> 31 << 24) | ((sdram->mc_mts_carveout_bom >> 20 << 12) | (sdram->mc_sec_carveout_size_mb & 0xFFF | (pmc->secure_scratch54 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch55 = (sdram->mc_generalized_carveout2_cfg0 << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 30) | ((32 * sdram->mc_video_protect_vpr_override1 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 6 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 15 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 16 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 17 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 18 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout4_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_mts_carveout_size_mb & 0xFFF | (pmc->secure_scratch55 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch56 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 30 >> 31 << 31) | (2 * (((u16)(sdram->mc_generalized_carveout1_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout2_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout2_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout2_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout2_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout2_cfg0 << 29 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout2_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout3_size_128kb & 0xFFF | (pmc->secure_scratch56 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); -// pmc->secure_scratch57 = ((u8)(sdram->mc_generalized_carveout3_cfg0) << 30 >> 31 << 31) | (2 * (((u8)(sdram->mc_generalized_carveout3_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout1_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout1_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout1_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout1_cfg0 << 29 >> 31 << 24) | ((sdram->mc_generalized_carveout5_size_128kb << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout1_size_128kb & 0xFFF | (pmc->secure_scratch57 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + s32(mc_generalized_carveout1_access0, secure_scratch59); + s32(mc_generalized_carveout1_access1, secure_scratch60); + s32(mc_generalized_carveout1_access2, secure_scratch61); + s32(mc_generalized_carveout1_access3, secure_scratch62); + s32(mc_generalized_carveout1_access4, secure_scratch63); + s32(mc_generalized_carveout2_access0, secure_scratch64); + s32(mc_generalized_carveout2_access1, secure_scratch65); + s32(mc_generalized_carveout2_access2, secure_scratch66); + s32(mc_generalized_carveout2_access3, secure_scratch67); + s32(mc_generalized_carveout2_access4, secure_scratch68); + s32(mc_generalized_carveout3_access0, secure_scratch69); + s32(mc_generalized_carveout3_access1, secure_scratch70); + s32(mc_generalized_carveout3_access2, secure_scratch71); + s32(mc_generalized_carveout3_access3, secure_scratch72); + s32(mc_generalized_carveout3_access4, secure_scratch73); + s32(mc_generalized_carveout4_access0, secure_scratch74); + s32(mc_generalized_carveout4_access1, secure_scratch75); + s32(mc_generalized_carveout4_access2, secure_scratch76); + s32(mc_generalized_carveout4_access3, secure_scratch77); + s32(mc_generalized_carveout4_access4, secure_scratch78); + s32(mc_generalized_carveout5_access0, secure_scratch79); + s32(mc_generalized_carveout5_access1, secure_scratch80); + s32(mc_generalized_carveout5_access2, secure_scratch81); + s32(mc_generalized_carveout5_access3, secure_scratch82); + s32(mc_generalized_carveout1_force_internal_access0, secure_scratch84); + s32(mc_generalized_carveout1_force_internal_access1, secure_scratch85); + s32(mc_generalized_carveout1_force_internal_access2, secure_scratch86); + s32(mc_generalized_carveout1_force_internal_access3, secure_scratch87); + s32(mc_generalized_carveout1_force_internal_access4, secure_scratch88); + s32(mc_generalized_carveout2_force_internal_access0, secure_scratch89); + s32(mc_generalized_carveout2_force_internal_access1, secure_scratch90); + s32(mc_generalized_carveout2_force_internal_access2, secure_scratch91); + s32(mc_generalized_carveout2_force_internal_access3, secure_scratch92); + s32(mc_generalized_carveout2_force_internal_access4, secure_scratch93); + s32(mc_generalized_carveout3_force_internal_access0, secure_scratch94); + s32(mc_generalized_carveout3_force_internal_access1, secure_scratch95); + s32(mc_generalized_carveout3_force_internal_access2, secure_scratch96); + s32(mc_generalized_carveout3_force_internal_access3, secure_scratch97); + s32(mc_generalized_carveout3_force_internal_access4, secure_scratch98); + s32(mc_generalized_carveout4_force_internal_access0, secure_scratch99); + s32(mc_generalized_carveout4_force_internal_access1, secure_scratch100); + s32(mc_generalized_carveout4_force_internal_access2, secure_scratch101); + s32(mc_generalized_carveout4_force_internal_access3, secure_scratch102); + s32(mc_generalized_carveout4_force_internal_access4, secure_scratch103); + s32(mc_generalized_carveout5_force_internal_access0, secure_scratch104); + s32(mc_generalized_carveout5_force_internal_access1, secure_scratch105); + s32(mc_generalized_carveout5_force_internal_access2, secure_scratch106); + s32(mc_generalized_carveout5_force_internal_access3, secure_scratch107); -// s32(mc_generalized_carveout1_access0, secure_scratch59); -// s32(mc_generalized_carveout1_access1, secure_scratch60); -// s32(mc_generalized_carveout1_access2, secure_scratch61); -// s32(mc_generalized_carveout1_access3, secure_scratch62); -// s32(mc_generalized_carveout1_access4, secure_scratch63); -// s32(mc_generalized_carveout2_access0, secure_scratch64); -// s32(mc_generalized_carveout2_access1, secure_scratch65); -// s32(mc_generalized_carveout2_access2, secure_scratch66); -// s32(mc_generalized_carveout2_access3, secure_scratch67); -// s32(mc_generalized_carveout2_access4, secure_scratch68); -// s32(mc_generalized_carveout3_access0, secure_scratch69); -// s32(mc_generalized_carveout3_access1, secure_scratch70); -// s32(mc_generalized_carveout3_access2, secure_scratch71); -// s32(mc_generalized_carveout3_access3, secure_scratch72); -// s32(mc_generalized_carveout3_access4, secure_scratch73); -// s32(mc_generalized_carveout4_access0, secure_scratch74); -// s32(mc_generalized_carveout4_access1, secure_scratch75); -// s32(mc_generalized_carveout4_access2, secure_scratch76); -// s32(mc_generalized_carveout4_access3, secure_scratch77); -// s32(mc_generalized_carveout4_access4, secure_scratch78); -// s32(mc_generalized_carveout5_access0, secure_scratch79); -// s32(mc_generalized_carveout5_access1, secure_scratch80); -// s32(mc_generalized_carveout5_access2, secure_scratch81); -// s32(mc_generalized_carveout5_access3, secure_scratch82); -// s32(mc_generalized_carveout1_force_internal_access0, secure_scratch84); -// s32(mc_generalized_carveout1_force_internal_access1, secure_scratch85); -// s32(mc_generalized_carveout1_force_internal_access2, secure_scratch86); -// s32(mc_generalized_carveout1_force_internal_access3, secure_scratch87); -// s32(mc_generalized_carveout1_force_internal_access4, secure_scratch88); -// s32(mc_generalized_carveout2_force_internal_access0, secure_scratch89); -// s32(mc_generalized_carveout2_force_internal_access1, secure_scratch90); -// s32(mc_generalized_carveout2_force_internal_access2, secure_scratch91); -// s32(mc_generalized_carveout2_force_internal_access3, secure_scratch92); -// s32(mc_generalized_carveout2_force_internal_access4, secure_scratch93); -// s32(mc_generalized_carveout3_force_internal_access0, secure_scratch94); -// s32(mc_generalized_carveout3_force_internal_access1, secure_scratch95); -// s32(mc_generalized_carveout3_force_internal_access2, secure_scratch96); -// s32(mc_generalized_carveout3_force_internal_access3, secure_scratch97); -// s32(mc_generalized_carveout3_force_internal_access4, secure_scratch98); -// s32(mc_generalized_carveout4_force_internal_access0, secure_scratch99); -// s32(mc_generalized_carveout4_force_internal_access1, secure_scratch100); -// s32(mc_generalized_carveout4_force_internal_access2, secure_scratch101); -// s32(mc_generalized_carveout4_force_internal_access3, secure_scratch102); -// s32(mc_generalized_carveout4_force_internal_access4, secure_scratch103); -// s32(mc_generalized_carveout5_force_internal_access0, secure_scratch104); -// s32(mc_generalized_carveout5_force_internal_access1, secure_scratch105); -// s32(mc_generalized_carveout5_force_internal_access2, secure_scratch106); -// s32(mc_generalized_carveout5_force_internal_access3, secure_scratch107); + pmc->secure_scratch58 = 32 * (32 * sdram->mc_generalized_carveout3_cfg0 >> 31) | (16 * (sdram->mc_generalized_carveout3_cfg0 << 6 >> 31) | (8 * (sdram->mc_generalized_carveout3_cfg0 << 7 >> 31) | (4 * (sdram->mc_generalized_carveout3_cfg0 << 8 >> 31) | (2 * (sdram->mc_generalized_carveout3_cfg0 << 9 >> 31) | ((sdram->mc_generalized_carveout3_cfg0 << 29 >> 31) | 2 * (pmc->secure_scratch58 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; -// pmc->secure_scratch58 = 32 * (32 * sdram->mc_generalized_carveout3_cfg0 >> 31) | (16 * (sdram->mc_generalized_carveout3_cfg0 << 6 >> 31) | (8 * (sdram->mc_generalized_carveout3_cfg0 << 7 >> 31) | (4 * (sdram->mc_generalized_carveout3_cfg0 << 8 >> 31) | (2 * (sdram->mc_generalized_carveout3_cfg0 << 9 >> 31) | ((sdram->mc_generalized_carveout3_cfg0 << 29 >> 31) | 2 * (pmc->secure_scratch58 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; + c32(0, scratch2); + s(pllm_input_divider, 7:0, scratch2, 7:0); + s(pllm_feedback_divider, 7:0, scratch2, 15:8); + s(pllm_post_divider, 4:0, scratch2, 20:16); + s(pllm_kvco, 0:0, scratch2, 17:17); + s(pllm_kcp, 1:0, scratch2, 19:18); -// c32(0, scratch2); -// s(pllm_input_divider, 7:0, scratch2, 7:0); -// s(pllm_feedback_divider, 7:0, scratch2, 15:8); -// s(pllm_post_divider, 4:0, scratch2, 20:16); -// s(pllm_kvco, 0:0, scratch2, 17:17); -// s(pllm_kcp, 1:0, scratch2, 19:18); + c32(0, scratch35); + s(pllm_setup_control, 15:0, scratch35, 15:0); -// c32(0, scratch35); -// s(pllm_setup_control, 15:0, scratch35, 15:0); + c32(0, scratch3); + s(pllm_input_divider, 7:0, scratch3, 7:0); + c(0x3e, scratch3, 15:8); + c(0, scratch3, 20:16); + s(pllm_kvco, 0:0, scratch3, 21:21); + s(pllm_kcp, 1:0, scratch3, 23:22); -// c32(0, scratch3); -// s(pllm_input_divider, 7:0, scratch3, 7:0); -// c(0x3e, scratch3, 15:8); -// c(0, scratch3, 20:16); -// s(pllm_kvco, 0:0, scratch3, 21:21); -// s(pllm_kcp, 1:0, scratch3, 23:22); + c32(0, scratch36); + s(pllm_setup_control, 23:0, scratch36, 23:0); -// c32(0, scratch36); -// s(PllMSetupControl, 23:0, scratch36, 23:0); - -// c32(0, scratch4); -// s(pllm_stable_time, 9:0, scratch4, 9:0); // s32(pllm_stable_time, scratch4);, s(pllm_stable_time, 31:0, scratch4, 31:10); -// s(pllm_stable_time, 31:0, scratch4, 31:10); -// } + c32(0, scratch4); + s(pllm_stable_time, 9:0, scratch4, 9:0); // s32(pllm_stable_time, scratch4);, s(pllm_stable_time, 31:0, scratch4, 31:10); + s(pllm_stable_time, 31:0, scratch4, 31:10); +} #pragma GCC diagnostic pop - +*/ void sdram_lp0_save_params(const void *params) { // u32 chip_id = (APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF; diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index ad13b87..1e9d01f 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -86,7 +87,16 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) kfuse_wait_ready(); if (type == TSEC_FW_TYPE_NEW) + { + // Disable all CCPLEX core rails. + pmc_enable_partition(POWER_RAIL_CE0, DISABLE); + pmc_enable_partition(POWER_RAIL_CE1, DISABLE); + pmc_enable_partition(POWER_RAIL_CE2, DISABLE); + pmc_enable_partition(POWER_RAIL_CE3, DISABLE); + + // Enable AHB aperture and set it to full mmio. mc_enable_ahb_redirect(true); + } // Configure Falcon. TSEC(TSEC_DMACTL) = 0; @@ -291,6 +301,7 @@ out:; bpmp_mmu_enable(); bpmp_clk_rate_set(prev_fid); + // Disable AHB aperture. if (type == TSEC_FW_TYPE_NEW) mc_disable_ahb_redirect(); diff --git a/bdk/soc/ccplex.c b/bdk/soc/ccplex.c index 894cb28..7d2f4b6 100644 --- a/bdk/soc/ccplex.c +++ b/bdk/soc/ccplex.c @@ -58,24 +58,7 @@ void ccplex_boot_cpu0(u32 entry) else _ccplex_enable_power_t210b01(); - // Enable PLLX and set it to 300 MHz. - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_ENABLE)) // PLLX_ENABLE. - { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. - usleep(2); - - // Bypass dividers. - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_BYPASS | (4 << 20) | (78 << 8) | 2; // P div: 4 (5), N div: 78, M div: 2. - // Disable bypass - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = (4 << 20) | (78 << 8) | 2; - // Set PLLX_LOCK_ENABLE. - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) = (CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) & 0xFFFBFFFF) | 0x40000; - // Enable PLLX. - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_ENABLE | (4 << 20) | (78 << 8) | 2; - } - // Wait for PLL to stabilize. - while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_LOCK)) - ; + clock_enable_pllx(); // Configure MSELECT source and enable clock to 102MHz. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c index 31bdb8f..f4d9e92 100644 --- a/bdk/soc/clock.c +++ b/bdk/soc/clock.c @@ -279,6 +279,32 @@ void clock_disable_pwm() clock_disable(&_clock_pwm); } +void clock_enable_pllx() +{ + // Configure and enable PLLX if disabled. + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_ENABLE)) // PLLX_ENABLE. + { + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ. + usleep(2); + + // Set div configuration. + const u32 pllx_div_cfg = (2 << 20) | (156 << 8) | 2; // P div: 2 (3), N div: 156, M div: 2. 998.4 MHz. + + // Bypass dividers. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_BYPASS | pllx_div_cfg; + // Disable bypass + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = pllx_div_cfg; + // Set PLLX_LOCK_ENABLE. + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= PLLX_MISC_LOCK_EN; + // Enable PLLX. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_ENABLE | pllx_div_cfg; + } + + // Wait for PLL to stabilize. + while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_LOCK)) + ; +} + void clock_enable_pllc(u32 divn) { u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; @@ -757,15 +783,25 @@ u32 clock_get_osc_freq() u32 clock_get_dev_freq(clock_pto_id_t id) { - u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (16 - 1); // 16 periods of 32.76KHz window. + const u32 pto_win = 16; + const u32 pto_osc = 32768; + + u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (pto_win - 1); CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); usleep(2); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN; - usleep(502); + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep((1000000 * pto_win / pto_osc) + 12 + 2); while (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY) ; @@ -773,9 +809,11 @@ u32 clock_get_dev_freq(clock_pto_id_t id) u32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT; CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep(2); - u32 freq = ((cnt << 8) | 0x3E) / 125; + u32 freq_khz = (u64)cnt * pto_osc / pto_win / 1000; - return freq; + return freq_khz; } diff --git a/bdk/soc/clock.h b/bdk/soc/clock.h index 67e9b4d..32afe8d 100644 --- a/bdk/soc/clock.h +++ b/bdk/soc/clock.h @@ -167,6 +167,8 @@ #define PLLX_BASE_REF_DIS BIT(29) #define PLLX_BASE_ENABLE BIT(30) #define PLLX_BASE_BYPASS BIT(31) +#define PLLX_MISC_LOCK_EN BIT(18) +#define PLLX_MISC3_IDDQ BIT(3) #define PLLCX_BASE_LOCK BIT(27) #define PLLCX_BASE_REF_DIS BIT(29) @@ -215,7 +217,7 @@ #define OSC_FREQ_DET_BUSY BIT(31) #define OSC_FREQ_DET_CNT 0xFFFF -/*! PLLs omitted as they need PTO enabled in MISC registers. Norm div is 2. */ +/*! PTO IDs. */ typedef enum _clock_pto_id_t { CLK_PTO_PCLK_SYS = 0x06, @@ -239,6 +241,9 @@ typedef enum _clock_pto_id_t CLK_PTO_SDMMC4 = 0x23, CLK_PTO_EMC = 0x24, + CLK_PTO_CCLK_LP = 0x2B, + CLK_PTO_CCLK_LP_DIV2 = 0x2C, + CLK_PTO_MSELECT = 0x2F, CLK_PTO_VIC = 0x36, @@ -321,6 +326,32 @@ typedef enum _clock_pto_id_t CLK_PTO_XUSB_SS_HOST_DEV = 0x137, CLK_PTO_XUSB_CORE_HOST = 0x138, CLK_PTO_XUSB_CORE_DEV = 0x139, + + /* + * PLL need PTO enabled in MISC registers. + * Normal div is 2 so result is multiplied with it. + */ + CLK_PTO_PLLC_DIV2 = 0x01, + CLK_PTO_PLLM_DIV2 = 0x02, + CLK_PTO_PLLP_DIV2 = 0x03, + CLK_PTO_PLLA_DIV2 = 0x04, + CLK_PTO_PLLX_DIV2 = 0x05, + + CLK_PTO_PLLMB_DIV2 = 0x25, + + CLK_PTO_PLLC4_DIV2 = 0x51, + + CLK_PTO_PLLA1_DIV2 = 0x55, + CLK_PTO_PLLC2_DIV2 = 0x58, + CLK_PTO_PLLC3_DIV2 = 0x5A, + + CLK_PTO_PLLD_DIV2 = 0xCB, + CLK_PTO_PLLD2_DIV2 = 0xCD, + CLK_PTO_PLLDP_DIV2 = 0xCF, + + CLK_PTO_PLLU_DIV2 = 0x10D, + + CLK_PTO_PLLREFE_DIV2 = 0x10F, } clock_pto_id_t; /* @@ -628,6 +659,7 @@ void clock_enable_coresight(); void clock_disable_coresight(); void clock_enable_pwm(); void clock_disable_pwm(); +void clock_enable_pllx(); void clock_enable_pllc(u32 divn); void clock_disable_pllc(); void clock_enable_pllu(); diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c index 5ceb2e7..4e4ebc9 100644 --- a/bdk/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -1033,12 +1033,10 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ } int result = _sdmmc_wait_response(sdmmc); - if (!result) - { #ifdef ERROR_EXTRA_PRINTING + if (!result) EPRINTF("SDMMC: Transfer timeout!"); #endif - } DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (result) @@ -1047,22 +1045,18 @@ DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, { sdmmc->expected_rsp_type = cmd->rsp_type; result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); - if (!result) - { #ifdef ERROR_EXTRA_PRINTING + if (!result) EPRINTF("SDMMC: Unknown response type!"); #endif - } } if (req && result) { result = _sdmmc_update_dma(sdmmc); - if (!result) - { #ifdef ERROR_EXTRA_PRINTING + if (!result) EPRINTF("SDMMC: DMA Update failed!"); #endif - } } } @@ -1085,12 +1079,10 @@ DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, if (cmd->check_busy || req) { result = _sdmmc_wait_card_busy(sdmmc); - if (!result) - { #ifdef ERROR_EXTRA_PRINTING + if (!result) EPRINTF("SDMMC: Busy timeout!"); #endif - } return result; } } From 070e085036bea899d953c55f467a611fac3debd6 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 19 Sep 2021 14:47:24 -0600 Subject: [PATCH 136/166] Bump version to v1.9.6 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 86de672..2c846cb 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,5 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 5 +LPVERSION_BUGFX := 6 LPVERSION_RSVD := 0 From 1c0fdd6e8ec784c114d1f4cb592dcdc07c40d37c Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 30 Nov 2021 11:38:59 -0700 Subject: [PATCH 137/166] main: Remove unused boot config setting --- source/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/main.c b/source/main.c index 2093dd2..cd8e92e 100644 --- a/source/main.c +++ b/source/main.c @@ -293,7 +293,6 @@ void dump_sysnand() { h_cfg.emummc_force_disable = true; emu_cfg.enabled = false; - b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } @@ -302,7 +301,6 @@ void dump_emunand() if (h_cfg.emummc_force_disable) return; emu_cfg.enabled = true; - b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } From e4661f035b7e8bac3ae126767d510a3900858586 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 30 Nov 2021 11:39:35 -0700 Subject: [PATCH 138/166] Update to hekate bdk 5.6.5 --- bdk/display/di.c | 20 +++-- bdk/display/di.h | 7 +- bdk/input/touch.c | 2 +- bdk/libs/fatfs/ff.c | 11 +-- bdk/mem/minerva.h | 4 +- bdk/mem/sdram.c | 10 +-- bdk/mem/sdram.h | 34 ++++---- bdk/mem/sdram_config_t210b01.inl | 41 ++++----- bdk/mem/smmu.c | 8 +- bdk/memory_map.h | 18 ++-- bdk/power/regulator_5v.c | 68 +++++++++++---- bdk/sec/tsec.c | 10 +-- bdk/soc/hw_init.c | 27 +++--- bdk/soc/hw_init.h | 5 +- bdk/soc/pmc.h | 7 ++ bdk/thermal/fan.c | 19 ++-- bdk/usb/usb_gadget_ums.c | 3 +- bdk/utils/types.h | 145 +++++++++++++++++++++---------- bdk/utils/util.c | 2 +- bdk/utils/util.h | 20 ++--- source/storage/emummc.c | 13 ++- source/storage/emummc.h | 2 +- 22 files changed, 299 insertions(+), 177 deletions(-) diff --git a/bdk/display/di.c b/bdk/display/di.c index ee4b45d..9396e99 100644 --- a/bdk/display/di.c +++ b/bdk/display/di.c @@ -436,12 +436,12 @@ void display_init() // For Aula ensure that we have a compatible panel id. if (nx_aula && _display_id == 0xCCCC) - _display_id = PANEL_SAM_70_UNK; + _display_id = PANEL_SAM_AMS699VC01; // Initialize display panel. switch (_display_id) { - case PANEL_SAM_70_UNK: + case PANEL_SAM_AMS699VC01: _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xA0, 0); // Write 0 to 0xA0. _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_SET_CONTROL_DISPLAY | (DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL << 8), 0); // Enable brightness control. @@ -539,7 +539,7 @@ void display_init() void display_backlight_pwm_init() { - if (_display_id == PANEL_SAM_70_UNK) + if (_display_id == PANEL_SAM_AMS699VC01) return; clock_enable_pwm(); @@ -557,6 +557,10 @@ void display_backlight(bool enable) void display_dsi_backlight_brightness(u32 brightness) { + // Normalize brightness value by 82% and a base of 45 duty. + if (brightness) + brightness = (brightness * PANEL_OLED_BL_COEFF / 100) + PANEL_OLED_BL_OFFSET; + u16 bl_ctrl = byte_swap_16((u16)(brightness * 8)); display_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl); } @@ -592,7 +596,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) if (brightness > 255) brightness = 255; - if (_display_id != PANEL_SAM_70_UNK) + if (_display_id != PANEL_SAM_AMS699VC01) display_pwm_backlight_brightness(brightness, step_delay); else display_dsi_backlight_brightness(brightness); @@ -624,7 +628,7 @@ static void _display_panel_and_hw_end(bool no_panel_deinit) exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17); exec_cfg((u32 *)DSI_BASE, _display_dsi_timing_deinit_config, 16); - if (_display_id != PANEL_SAM_70_UNK) + if (_display_id != PANEL_SAM_AMS699VC01) usleep(10000); // De-initialize display panel. @@ -678,7 +682,7 @@ static void _display_panel_and_hw_end(bool no_panel_deinit) // Blank - powerdown. _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, - (_display_id == PANEL_SAM_70_UNK) ? 120000 : 50000); + (_display_id == PANEL_SAM_AMS699VC01) ? 120000 : 50000); skip_panel_deinit: // Disable LCD power pins. @@ -734,7 +738,7 @@ void display_set_decoded_panel_id(u32 id) // For Aula ensure that we have a compatible panel id. if (nx_aula && _display_id == 0xCCCC) - _display_id = PANEL_SAM_70_UNK; + _display_id = PANEL_SAM_AMS699VC01; } void display_color_screen(u32 color) @@ -749,7 +753,7 @@ void display_color_screen(u32 color) DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; usleep(35000); // No need to wait on Aula. - if (_display_id != PANEL_SAM_70_UNK) + if (_display_id != PANEL_SAM_AMS699VC01) display_backlight(true); else display_backlight_brightness(255, 0); diff --git a/bdk/display/di.h b/bdk/display/di.h index 9229a22..1e0f991 100644 --- a/bdk/display/di.h +++ b/bdk/display/di.h @@ -652,6 +652,9 @@ #define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) #define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5) +#define PANEL_OLED_BL_COEFF 82 // 82%. +#define PANEL_OLED_BL_OFFSET 45 // Least legible backlight duty. + /* Switch Panels: * * 6.2" panels for Icosa and Iowa skus: @@ -671,7 +674,7 @@ * [40] XX [10]: Vendor 40 [UNCONFIRMED ID] * * 7.0" OLED panels for Aula skus: - * [50] XX [20]: Samsung AMS700XXXX [UNCONFIRMED ID and MODEL] + * [50] 9B [20]: Samsung AMS699VC01-0 (Rev 2.5) */ /* Display ID Decoding: @@ -703,7 +706,7 @@ enum PANEL_INL_2J055IA_27A = 0x1020, PANEL_AUO_A055TAN01 = 0x1030, PANEL_V40_55_UNK = 0x1040, - PANEL_SAM_70_UNK = 0x2050 + PANEL_SAM_AMS699VC01 = 0x2050 }; void display_init(); diff --git a/bdk/input/touch.c b/bdk/input/touch.c index 2aba0e4..4c49837 100644 --- a/bdk/input/touch.c +++ b/bdk/input/touch.c @@ -39,7 +39,7 @@ static touch_panel_info_t _panels[] = { 1, 0, 1, 1, "GiS GGM6 B2X" }, { 2, 0, 0, 0, "NISSHA NBF-K9A" }, { 3, 1, 0, 0, "GiS 5.5\"" }, - { 4, 0, 0, 1, "Unknown_001" }, + { 4, 0, 0, 1, "Samsung BH2109" }, { -1, 1, 0, 1, "GiS VA 6.2\"" } }; diff --git a/bdk/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c index 75e0271..08e800f 100644 --- a/bdk/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -3274,7 +3274,6 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ stat = disk_status(fs->pdrv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ - EFSPRINTF("WPEN1"); return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is valid */ @@ -3289,11 +3288,9 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ - EFSPRINTF("MDNR"); return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ - EFSPRINTF("WPEN2"); return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ @@ -4712,9 +4709,9 @@ DWORD *f_expand_cltbl ( } if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ ff_memfree(fp->cltbl); - fp->cltbl = NULL; + fp->cltbl = (void *)0; EFSPRINTF("CLTBLSZ"); - return NULL; + return (void *)0; } f_lseek(fp, 0); @@ -6737,6 +6734,8 @@ int f_puts ( putbuff pb; + if (str == (void *)0) return EOF; /* String is NULL */ + putc_init(&pb, fp); while (*str) putc_bfd(&pb, *str++); /* Put the string */ return putc_flush(&pb); @@ -6763,6 +6762,8 @@ int f_printf ( TCHAR c, d, str[32], *p; + if (fmt == (void *)0) return EOF; /* String is NULL */ + putc_init(&pb, fp); va_start(arp, fmt); diff --git a/bdk/mem/minerva.h b/bdk/mem/minerva.h index 51cb215..a81cdc8 100644 --- a/bdk/mem/minerva.h +++ b/bdk/mem/minerva.h @@ -27,8 +27,8 @@ typedef struct { - s32 rate_to; - s32 rate_from; + u32 rate_to; + u32 rate_from; emc_table_t *mtc_table; u32 table_entries; emc_table_t *current_emc_table; diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c index 0f2ce3e..00ec355 100644 --- a/bdk/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -55,11 +55,11 @@ static const u8 dram_encoding_t210b01[] = { LPDDR4X_NO_PATCH, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, LPDDR4X_NO_PATCH, - LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE, LPDDR4X_NO_PATCH, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, LPDDR4X_NO_PATCH, - LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE, LPDDR4X_4GB_SAMSUNG_Y, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, @@ -69,9 +69,9 @@ static const u8 dram_encoding_t210b01[] = { LPDDR4X_UNUSED, // Removed. LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, - LPDDR4X_4GB_MICRON_1Y_A, - LPDDR4X_4GB_MICRON_1Y_A, - LPDDR4X_4GB_MICRON_1Y_A, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, }; diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h index 3caac47..42907f9 100644 --- a/bdk/mem/sdram.h +++ b/bdk/mem/sdram.h @@ -50,7 +50,7 @@ enum sdram_ids_erista // LPDDR4 3200Mbps. LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, - LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, + LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, // WT:C. LPDDR4_COPPER_4GB_SAMSUNG_K4F6E304HB_MGCH = 3, // Changed to Iowa Hynix 4GB 1Y-A. LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, LPDDR4_COPPER_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 5, // Changed to Hoag Hynix 4GB 1Y-A. @@ -70,12 +70,12 @@ enum sdram_ids_mariko LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, // Die-M. LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, // Die-M. LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, // Die-M. - LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WT = 11, // 4266Mbps. WT:E. Die-E. + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, // 4266Mbps. Die-E. LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, // Die-M. LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, // Die-M. LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, // Die-M. - LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WT = 15, // 4266Mbps. WT:E. Die-E. + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, // 4266Mbps. Die-E. // LPDDR4X 4266Mbps. LPDDR4X_IOWA_4GB_SAMSUNG_Y = 16, @@ -92,9 +92,9 @@ enum sdram_ids_mariko LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. - LPDDR4X_IOWA_4GB_MICRON_1Y_A = 25, - LPDDR4X_HOAG_4GB_MICRON_1Y_A = 26, - LPDDR4X_AULA_4GB_MICRON_1Y_A = 27, + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, // 4266Mbps. Die-F. + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, // 4266Mbps. Die-F. + LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, // 4266Mbps. Die-F. LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, // Die-A. }; @@ -107,17 +107,17 @@ enum sdram_codes_mariko // LPDDR4X_4GB_SAMSUNG_K4U6E3S4AM_MGCJ DRAM IDs: 08, 12. // LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLHR_NME DRAM IDs: 10, 14. - LPDDR4X_4GB_SAMSUNG_X1X2 = 1, // DRAM IDs: 07. - LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 2, // DRAM IDs: 09, 13. - LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 = 3, // DRAM IDs: 11, 15. - LPDDR4X_4GB_SAMSUNG_Y = 4, // DRAM IDs: 16. - LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 5, // DRAM IDs: 17, 19, 24. - LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 6, // DRAM IDs: 18, 23, 28. - LPDDR4X_4GB_SAMSUNG_1Y_Y = 7, // DRAM IDs: 20. - LPDDR4X_8GB_SAMSUNG_1Y_Y = 8, // DRAM IDs: 21. - //LPDDR4X_8GB_SAMSUNG_1Y_A = 9, // DRAM IDs: 22. Unused. - LPDDR4X_4GB_MICRON_1Y_A = 10, // DRAM IDs: 25, 26, 27. - LPDDR4X_4GB_HYNIX_1Y_A = 11, // DRAM IDs: 03, 05, 06. + LPDDR4X_4GB_SAMSUNG_X1X2 = 1, // DRAM IDs: 07. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 2, // DRAM IDs: 09, 13. + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE = 3, // DRAM IDs: 11, 15. + LPDDR4X_4GB_SAMSUNG_Y = 4, // DRAM IDs: 16. + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 5, // DRAM IDs: 17, 19, 24. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 6, // DRAM IDs: 18, 23, 28. + LPDDR4X_4GB_SAMSUNG_1Y_Y = 7, // DRAM IDs: 20. + LPDDR4X_8GB_SAMSUNG_1Y_Y = 8, // DRAM IDs: 21. + //LPDDR4X_8GB_SAMSUNG_1Y_A = 9, // DRAM IDs: 22. Unused. + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF = 10, // DRAM IDs: 25, 26, 27. + LPDDR4X_4GB_HYNIX_1Y_A = 11, // DRAM IDs: 03, 05, 06. }; void sdram_init(); diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl index 0d1d617..28cc063 100644 --- a/bdk/mem/sdram_config_t210b01.inl +++ b/bdk/mem/sdram_config_t210b01.inl @@ -769,13 +769,13 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x2A800000, 0x6DC / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_video_protect_gpu_override0. { 0x00000002, 0x6E0 / 4, LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ }, // mc_video_protect_gpu_override1. - // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT Die-E for retail Iowa and Hoag. - { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_auto_cal_vref_sel0. - { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_mrw14. - { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // emc_dyn_self_ref_control. - { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046 }, // mc_video_protect_gpu_override1. + // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT:E Die-E for retail Iowa and Hoag. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // emc_auto_cal_vref_sel0. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // emc_dyn_self_ref_control. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE }, // mc_video_protect_gpu_override1. // Samsung LPDDR4X 4GB (Y01) Die-? for Iowa. { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_SAMSUNG_Y }, // emc_auto_cal_config2. @@ -957,19 +957,20 @@ static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { { 0x00000002, 0x680 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_arb_timing_r2r. { 0x02020001, 0x694 / 4, LPDDR4X_8GB_SAMSUNG_1Y_A }, // mc_emem_arb_da_turns. */ - // Micron LPDDR4X 4GB 10nm-class (1y-01) Die-A for Unknown Iowa/Hoag/Aula. - { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_auto_cal_config2. - { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_auto_cal_vref_sel0. - { 0x00000006, 0x1CC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_quse. - { 0x00000005, 0x1D0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_quse_width. - { 0x00000003, 0x1DC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_einput. - { 0x0000000C, 0x1E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_einput_duration. - { 0x00000008, 0x24C / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_tfaw. - { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_mrw14. - { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_1Y_A }, // emc_dyn_self_ref_control. - { 0x00000001, 0x670 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_emem_arb_timing_faw. - { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_video_protect_gpu_override0. - { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_1Y_A }, // mc_video_protect_gpu_override1. + + // Micron LPDDR4X 4GB MT53D1024M32D1NP-053-WT:F 10nm-class (1y-01) Die-F for Newer Iowa/Hoag/Aula. + { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_auto_cal_config2. + { 0xC9AFBCBC, 0x0F4 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_auto_cal_vref_sel0. + { 0x00000006, 0x1CC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_quse. + { 0x00000005, 0x1D0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_quse_width. + { 0x00000003, 0x1DC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_einput. + { 0x0000000C, 0x1E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_einput_duration. + { 0x00000008, 0x24C / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_tfaw. + { 0x88161414, 0x2E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_mrw14. + { 0x80000713, 0x32C / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // emc_dyn_self_ref_control. + { 0x00000001, 0x670 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // mc_emem_arb_timing_faw. + { 0x2A800000, 0x6DC / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // mc_video_protect_gpu_override0. + { 0x00000002, 0x6E0 / 4, LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF }, // mc_video_protect_gpu_override1. // Hynix LPDDR4X 4GB 10nm-class (1y-01) Die-A for Unknown Iowa/Hoag/Aula. { 0x05500000, 0x0D4 / 4, LPDDR4X_4GB_HYNIX_1Y_A }, // emc_auto_cal_config2. diff --git a/bdk/mem/smmu.c b/bdk/mem/smmu.c index 6ee99b9..f2f20fb 100644 --- a/bdk/mem/smmu.c +++ b/bdk/mem/smmu.c @@ -48,8 +48,8 @@ u8 smmu_payload[] __attribute__((aligned(16))) = { void *page_alloc(u32 num) { u8 *res = _pageheap; - _pageheap += 0x1000 * num; - memset(res, 0, 0x1000 * num); + _pageheap += SZ_PAGE * num; + memset(res, 0, SZ_PAGE * num); return res; } @@ -150,8 +150,8 @@ void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr) { u32 *pte = smmu_get_pte(pdir, addr); *pte = SMMU_ADDR_TO_PFN(page) | attr; - addr += 0x1000; - page += 0x1000; + addr += SZ_PAGE; + page += SZ_PAGE; } smmu_flush_all(); } diff --git a/bdk/memory_map.h b/bdk/memory_map.h index 70f1354..4303ddd 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -23,7 +23,7 @@ #define LDR_LOAD_ADDR 0x40007000 #define IPL_LOAD_ADDR 0x40008000 -#define IPL_SZ_MAX 0x20000 // 128KB. +#define IPL_SZ_MAX SZ_128K /* --- XUSB EP context and TRB ring buffers --- */ #define XUSB_RING_ADDR 0x40020000 @@ -35,16 +35,16 @@ /* --- DRAM START --- */ #define DRAM_START 0x80000000 -#define HOS_RSVD 0x1000000 // Do not write anything in this area. +#define HOS_RSVD SZ_16M // Do not write anything in this area. #define NYX_LOAD_ADDR 0x81000000 -#define NYX_SZ_MAX 0x1000000 // 16MB +#define NYX_SZ_MAX SZ_16M /* --- Gap: 0x82000000 - 0x82FFFFFF --- */ /* Stack theoretical max: 33MB */ #define IPL_STACK_TOP 0x83100000 #define IPL_HEAP_START 0x84000000 -#define IPL_HEAP_SZ 0x20000000 // 512MB. +#define IPL_HEAP_SZ SZ_512M /* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */ // Virtual disk / Chainloader buffers. @@ -60,26 +60,26 @@ // L4T Kernel Panic Storage (PSTORE). #define PSTORE_ADDR 0xB0000000 -#define PSTORE_SZ 0x200000 // 2MB. +#define PSTORE_SZ SZ_2M //#define DRAM_LIB_ADDR 0xE0000000 /* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. // SDMMC DMA buffers 1 #define SDMMC_UPPER_BUFFER 0xE5000000 -#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. +#define SDMMC_UP_BUF_SZ SZ_128M // Nyx buffers. #define NYX_STORAGE_ADDR 0xED000000 #define NYX_RES_ADDR 0xEE000000 -#define NYX_RES_SZ 0x1000000 // 16MB. +#define NYX_RES_SZ SZ_16M // SDMMC DMA buffers 2 #define SDXC_BUF_ALIGNED 0xEF000000 #define MIXD_BUF_ALIGNED 0xF0000000 #define TITLEKEY_BUF_ADR MIXD_BUF_ALIGNED #define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED -#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). +#define SDMMC_DMA_BUF_SZ SZ_16M // 4MB currently used. // Nyx LvGL buffers. #define NYX_LV_VDB_ADR 0xF1000000 @@ -107,7 +107,7 @@ #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 +#define USB_EP_BULK_OUT_MAX_XFER SZ_8M // #define EXT_PAYLOAD_ADDR 0xC0000000 // #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) diff --git a/bdk/power/regulator_5v.c b/bdk/power/regulator_5v.c index 7b8924b..379f7a6 100644 --- a/bdk/power/regulator_5v.c +++ b/bdk/power/regulator_5v.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,7 +14,9 @@ * along with this program. If not, see . */ +#include #include +#include #include #include #include @@ -34,17 +36,30 @@ void regulator_5v_enable(u8 dev) 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 VBUS. - 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_LOW); - usb_src = false; + // Only Icosa and Iowa have USB 5V VBUS rails. Skip on Hoag/Aula. + u32 hw_type = fuse_read_hw_type(); + if (hw_type == FUSE_NX_HW_TYPE_ICOSA || + hw_type == FUSE_NX_HW_TYPE_IOWA) + { + // Fan and Rail power from USB 5V VBUS. + 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_LOW); + } - // 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; + // Enable GPIO AO IO rail for T210. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + // Make sure GPIO power is enabled. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN; + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. + + // Override power detect for GPIO AO IO rails. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + } + usb_src = false; } reg_5v_dev |= dev; } @@ -61,15 +76,26 @@ void regulator_5v_disable(u8 dev) 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 VBUS. - 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; - usb_src = false; + // Only Icosa and Iowa have USB 5V VBUS rails. Skip on Hoag/Aula. + u32 hw_type = fuse_read_hw_type(); + if (hw_type == FUSE_NX_HW_TYPE_ICOSA || + hw_type == FUSE_NX_HW_TYPE_IOWA) + { + // Rail power from USB 5V VBUS. + 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; + usb_src = false; + + } // GPIO AO IO rails. - PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN; + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + } } } @@ -80,6 +106,12 @@ bool regulator_5v_get_dev_enabled(u8 dev) void regulator_5v_usb_src_enable(bool enable) { + // Only for Icosa/Iowa. Skip on Hoag/Aula. + u32 hw_type = fuse_read_hw_type(); + if (hw_type != FUSE_NX_HW_TYPE_ICOSA && + hw_type != FUSE_NX_HW_TYPE_IOWA) + return; + if (enable && !usb_src) { gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH); diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index 1e9d01f..50a90ae 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -125,7 +125,7 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; else { - fwbuf = (u8 *)malloc(0x4000); + fwbuf = (u8 *)malloc(SZ_16K); u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100); memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size); TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8; @@ -151,13 +151,13 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) // Clock reset controller. car = page_alloc(1); - memcpy(car, (void *)CLOCK_BASE, 0x1000); + memcpy(car, (void *)CLOCK_BASE, SZ_PAGE); car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); // Fuse driver. fuse = page_alloc(1); - memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); + memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K); fuse[0x82C / 4] = 0; fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; @@ -173,12 +173,12 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) // Security engine. se = page_alloc(1); - memcpy(se, (void *)SE_BASE, 0x1000); + memcpy(se, (void *)SE_BASE, SZ_PAGE); smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); // Memory controller. mc = page_alloc(1); - memcpy(mc, (void *)MC_BASE, 0x1000); + memcpy(mc, (void *)MC_BASE, SZ_PAGE); mc[MC_IRAM_BOM / 4] = 0; mc[MC_IRAM_TOM / 4] = 0x80000000; smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index 5efe5df..c86dc3a 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -48,14 +48,8 @@ extern boot_cfg_t b_cfg; extern volatile nyx_storage_t *nyx_str; -/* - * CLK_OSC - 38.4 MHz crystal. - * CLK_M - 19.2 MHz (osc/2). - * CLK_S - 32.768 KHz (from PMIC). - * SCLK - 204MHz init (-> 408MHz -> OC). - * HCLK - 204MHz init (-> 408MHz -> OC). - * PCLK - 68MHz init (-> 136MHz -> OC/4). - */ +u32 hw_rst_status; +u32 hw_rst_reason; u32 hw_get_chip_id() { @@ -65,6 +59,15 @@ u32 hw_get_chip_id() return GP_HIDREV_MAJOR_T210; } +/* + * CLK_OSC - 38.4 MHz crystal. + * CLK_M - 19.2 MHz (osc/2). + * CLK_S - 32.768 KHz (from PMIC). + * SCLK - 204MHz init (-> 408MHz -> OC). + * HCLK - 204MHz init (-> 408MHz -> OC). + * PCLK - 68MHz init (-> 136MHz -> OC/4). + */ + static void _config_oscillators() { CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. @@ -260,11 +263,15 @@ static void _config_se_brom() // se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); // This memset needs to happen here, else TZRAM will behave weirdly later on. - memset((void *)TZRAM_BASE, 0, 0x10000); + memset((void *)TZRAM_BASE, 0, SZ_64K); PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; SE(SE_INT_STATUS_REG) = 0x1F; // Clear all SE interrupts. - // Clear the boot reason to avoid problems later + // Save reset reason. + hw_rst_status = PMC(APBDEV_PMC_SCRATCH200); + hw_rst_reason = PMC(APBDEV_PMC_RST_STATUS) & PMC_RST_STATUS_MASK; + + // Clear the boot reason to avoid problems later. PMC(APBDEV_PMC_SCRATCH200) = 0x0; PMC(APBDEV_PMC_RST_STATUS) = 0x0; APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); diff --git a/bdk/soc/hw_init.h b/bdk/soc/hw_init.h index a1b2dfc..4a24c33 100644 --- a/bdk/soc/hw_init.h +++ b/bdk/soc/hw_init.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,6 +23,9 @@ #define BL_MAGIC_CRBOOT_SLD 0x30444C53 // SLD0, seamless display type 0. #define BL_MAGIC_BROKEN_HWI 0xBAADF00D // Broken hwinit. +extern u32 hw_rst_status; +extern u32 hw_rst_reason; + void hw_init(); void hw_reinit_workaround(bool coreboot, u32 magic); u32 hw_get_chip_id(); diff --git a/bdk/soc/pmc.h b/bdk/soc/pmc.h index 42bd869..937786a 100644 --- a/bdk/soc/pmc.h +++ b/bdk/soc/pmc.h @@ -60,6 +60,13 @@ #define APBDEV_PMC_CLK_OUT_CNTRL 0x1A8 #define PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN BIT(2) #define APBDEV_PMC_RST_STATUS 0x1B4 +#define PMC_RST_STATUS_MASK 0x7 +#define PMC_RST_STATUS_POR 0 +#define PMC_RST_STATUS_WATCHDOG 1 +#define PMC_RST_STATUS_SENSOR 2 +#define PMC_RST_STATUS_SW_MAIN 3 +#define PMC_RST_STATUS_LP0 4 +#define PMC_RST_STATUS_AOTAG 5 #define APBDEV_PMC_IO_DPD_REQ 0x1B8 #define PMC_IO_DPD_REQ_DPD_OFF BIT(30) #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c index 14379e3..9e7a65e 100644 --- a/bdk/thermal/fan.c +++ b/bdk/thermal/fan.c @@ -1,7 +1,7 @@ /* * Fan driver for Nintendo Switch * - * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -28,9 +29,20 @@ void set_fan_duty(u32 duty) static bool fan_init = false; static u16 curr_duty = -1; + if (duty > 236) + duty = 236; + if (curr_duty == duty) return; + curr_duty = duty; + + //! TODO: Add HOAG/AULA support. + u32 hw_type = fuse_read_hw_type(); + if (hw_type != FUSE_NX_HW_TYPE_ICOSA && + hw_type != FUSE_NX_HW_TYPE_IOWA) + return; + if (!fan_init) { // Fan tachometer. @@ -46,9 +58,6 @@ void set_fan_duty(u32 duty) fan_init = true; } - if (duty > 236) - duty = 236; - // Inverted polarity. u32 inv_duty = 236 - duty; @@ -71,8 +80,6 @@ void set_fan_duty(u32 duty) // Enable fan. PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. } - - curr_duty = duty; } void get_fan_speed(u32 *duty, u32 *rpm) diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c index 4be2436..2b90439 100644 --- a/bdk/usb/usb_gadget_ums.c +++ b/bdk/usb/usb_gadget_ums.c @@ -1092,8 +1092,7 @@ static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) // Notify for possible unmounting? // Normally we sync here but we do synced writes to SDMMC. - if (ums->lun.prevent_medium_removal && !prevent) - ; + if (ums->lun.prevent_medium_removal && !prevent) { /* Do nothing */ } ums->lun.prevent_medium_removal = prevent; diff --git a/bdk/utils/types.h b/bdk/utils/types.h index b9c269e..4fc0101 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -20,10 +20,84 @@ #include +/* Types */ +typedef signed char s8; +typedef short s16; +typedef short SHORT; +typedef int s32; +typedef int INT; +typedef int bool; +typedef long LONG; +typedef long long int s64; + +typedef unsigned char u8; +typedef unsigned char BYTE; +typedef unsigned short u16; +typedef unsigned short WORD; +typedef unsigned short WCHAR; +typedef unsigned int u32; +typedef unsigned int UINT; +typedef unsigned long DWORD; +typedef unsigned long long QWORD; +typedef unsigned long long int u64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; + +#ifdef __aarch64__ +typedef u64 uptr; +#else /* __arm__ or __thumb__ */ +typedef u32 uptr; +#endif + +/* Colors */ +#define COLOR_RED 0xFFE70000 +#define COLOR_ORANGE 0xFFFF8C00 +#define COLOR_YELLOW 0xFFFFFF40 +#define COLOR_GREEN 0xFF40FF00 +#define COLOR_BLUE 0xFF00DDFF +#define COLOR_VIOLET 0xFF8040FF + +static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; + +/* Important */ +#define false 0 +#define true 1 + #define NULL ((void *)0) -#define ALWAYS_INLINE inline __attribute__((always_inline)) +/* Misc */ +#define DISABLE 0 +#define ENABLE 1 +/* Sizes */ +#define SZ_1K 0x400 +#define SZ_2K 0x800 +#define SZ_4K 0x1000 +#define SZ_8K 0x2000 +#define SZ_16K 0x4000 +#define SZ_32K 0x8000 +#define SZ_64K 0x10000 +#define SZ_128K 0x20000 +#define SZ_256K 0x40000 +#define SZ_512K 0x80000 +#define SZ_1M 0x100000 +#define SZ_2M 0x200000 +#define SZ_4M 0x400000 +#define SZ_8M 0x800000 +#define SZ_16M 0x1000000 +#define SZ_32M 0x2000000 +#define SZ_64M 0x4000000 +#define SZ_128M 0x8000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 +#define SZ_PAGE SZ_4K + +/* Macros */ +#define ALWAYS_INLINE inline __attribute__((always_inline)) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define ALIGN_DOWN(x, a) ((x) & ~((a) - 1)) #define BIT(n) (1U << (n)) @@ -36,58 +110,37 @@ #define CLZ(n) __builtin_clz(n) #define CLO(n) __builtin_clz(~n) -#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) -#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) +#define OFFSET_OF(t, m) ((uptr)&((t *)NULL)->m) +#define CONTAINER_OF(mp, t, mn) ((t *)((uptr)mp - OFFSET_OF(t, mn))) -#define COLOR_RED 0xFFE70000 -#define COLOR_ORANGE 0xFFFF8C00 -#define COLOR_YELLOW 0xFFFFFF40 -#define COLOR_GREEN 0xFF40FF00 -#define COLOR_BLUE 0xFF00DDFF -#define COLOR_VIOLET 0xFF8040FF +#define byte_swap_16(num) ((((num) >> 8) & 0xff) | (((num) << 8) & 0xff00)) +#define byte_swap_32(num) ((((num) >> 24) & 0xff) | (((num) << 8) & 0xff0000) | \ + (((num) >> 8 )& 0xff00) | (((num) << 24) & 0xff000000)) -typedef signed char s8; -typedef short s16; -typedef short SHORT; -typedef int s32; -typedef int INT; -typedef long LONG; -typedef long long int s64; -typedef unsigned char u8; -typedef unsigned char BYTE; -typedef unsigned short u16; -typedef unsigned short WORD; -typedef unsigned short WCHAR; -typedef unsigned int u32; -typedef unsigned int UINT; -typedef unsigned long DWORD; -typedef unsigned long long QWORD; -typedef unsigned long long int u64; -typedef volatile unsigned char vu8; -typedef volatile unsigned short vu16; -typedef volatile unsigned int vu32; - -#ifdef __aarch64__ -typedef u64 uptr; -#else /* __arm__ or __thumb__ */ -typedef u32 uptr; -#endif - -static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; - -typedef int bool; -#define true 1 -#define false 0 - -#define DISABLE 0 -#define ENABLE 1 +/* Bootloader/Nyx */ #define BOOT_CFG_AUTOBOOT_EN BIT(0) #define BOOT_CFG_FROM_LAUNCH BIT(1) #define BOOT_CFG_FROM_ID BIT(2) #define BOOT_CFG_TO_EMUMMC BIT(3) -#define EXTRA_CFG_DUMP_EMUMMC BIT(0) +#define EXTRA_CFG_KEYS BIT(0) +#define EXTRA_CFG_PAYLOAD BIT(1) +#define EXTRA_CFG_MODULE BIT(2) + +#define EXTRA_CFG_NYX_UMS BIT(5) +#define EXTRA_CFG_NYX_RELOAD BIT(6) + +typedef enum _nyx_ums_type +{ + NYX_UMS_SD_CARD = 0, + NYX_UMS_EMMC_BOOT0, + NYX_UMS_EMMC_BOOT1, + NYX_UMS_EMMC_GPP, + NYX_UMS_EMUMMC_BOOT0, + NYX_UMS_EMUMMC_BOOT1, + NYX_UMS_EMUMMC_GPP +} nyx_ums_type; typedef struct __attribute__((__packed__)) _boot_cfg_t { @@ -107,7 +160,7 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t }; } boot_cfg_t; -static_assert(sizeof(boot_cfg_t) == 0x84, "Boot CFG size is wrong!"); +static_assert(sizeof(boot_cfg_t) == 0x84, "Boot cfg storage size is wrong!"); typedef struct __attribute__((__packed__)) _ipl_ver_meta_t { diff --git a/bdk/utils/util.c b/bdk/utils/util.c index 2c21b28..146c404 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018-2021 CTCaer +* Copyright (c) 2018-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, diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 213d9cf..d3d391f 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -21,6 +21,8 @@ #include #include +#define NYX_NEW_INFO 0x3058594E + typedef enum { REBOOT_RCM, // PMC reset. Enter RCM mode. @@ -33,9 +35,9 @@ typedef enum typedef enum { - NYX_CFG_BIS = BIT(5), NYX_CFG_UMS = BIT(6), - NYX_CFG_DUMP = BIT(7), + + NYX_CFG_EXTRA = 0xFF << 24 } nyx_cfg_t; typedef enum @@ -44,15 +46,11 @@ typedef enum ERR_SYSOLD_NYX = BIT(1), ERR_LIBSYS_MTC = BIT(2), ERR_SD_BOOT_EN = BIT(3), + ERR_PANIC_CODE = BIT(4), ERR_L4T_KERNEL = BIT(24), ERR_EXCEPTION = BIT(31), } hekate_errors_t; -#define byte_swap_32(num) ((((num) >> 24) & 0xff) | (((num) << 8) & 0xff0000) | \ - (((num) >> 8 )& 0xff00) | (((num) << 24) & 0xff000000)) - -#define byte_swap_16(num) ((((num) >> 8) & 0xff) | (((num) << 8) & 0xff00)) - typedef struct _cfg_op_t { u32 off; @@ -75,7 +73,7 @@ typedef struct _nyx_storage_t u32 cfg; u8 irama[0x8000]; u8 hekate[0x30000]; - u8 rsvd[0x800000 - sizeof(nyx_info_t)]; + u8 rsvd[SZ_8M - sizeof(nyx_info_t)]; nyx_info_t info; mtc_config_t mtc_cfg; emc_table_t mtc_table[10]; @@ -87,9 +85,9 @@ u32 bit_count_mask(u8 bits); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); u32 crc32_calc(u32 crc, const u8 *buf, u32 len); -u32 get_tmr_us(); -u32 get_tmr_ms(); -u32 get_tmr_s(); +u32 get_tmr_us(); +u32 get_tmr_ms(); +u32 get_tmr_s(); void usleep(u32 us); void msleep(u32 ms); diff --git a/source/storage/emummc.c b/source/storage/emummc.c index 52a748e..fc44be3 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -42,9 +42,9 @@ void emummc_load_cfg() emu_cfg.active_part = 0; emu_cfg.fs_ver = 0; if (!emu_cfg.nintendo_path) - emu_cfg.nintendo_path = (char *)malloc(0x80); + emu_cfg.nintendo_path = (char *)malloc(0x200); if (!emu_cfg.emummc_file_based_path) - emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + emu_cfg.emummc_file_based_path = (char *)malloc(0x200); emu_cfg.nintendo_path[0] = 0; emu_cfg.emummc_file_based_path[0] = 0; @@ -109,7 +109,14 @@ bool emummc_set_path(char *path) if (found) { emu_cfg.enabled = 1; - emu_cfg.id = 0; + + // Get ID from path. + u32 id_from_path = 0; + u32 path_size = strlen(path); + if (path_size >= 4) + memcpy(&id_from_path, path + path_size - 4, 4); + emu_cfg.id = id_from_path; + strcpy(emu_cfg.nintendo_path, path); strcat(emu_cfg.nintendo_path, "/Nintendo"); } diff --git a/source/storage/emummc.h b/source/storage/emummc.h index e8b1d32..7e162fd 100644 --- a/source/storage/emummc.h +++ b/source/storage/emummc.h @@ -37,7 +37,7 @@ typedef struct _emummc_cfg_t { int enabled; u64 sector; - u16 id; + u32 id; char *path; char *nintendo_path; // Internal. From 54ed439ccefcce8abe04a1479ce562b2c77d08d7 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Feb 2022 10:52:21 -0700 Subject: [PATCH 139/166] Use size abbreviations --- bdk/libs/nx_savedata/header.h | 4 ++-- bdk/libs/nx_savedata/remap_storage.h | 2 +- bdk/libs/nx_savedata/save_fs_list.c | 2 +- source/keys/keys.c | 14 +++++++------- source/keys/keys.h | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bdk/libs/nx_savedata/header.h b/bdk/libs/nx_savedata/header.h index 3d65d83..4a6e259 100644 --- a/bdk/libs/nx_savedata/header.h +++ b/bdk/libs/nx_savedata/header.h @@ -61,7 +61,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define VERSION_RMAP 0x10000 #define VERSION_IVFC 0x20000 -#define SAVE_BLOCK_SIZE_DEFAULT 0x4000 +#define SAVE_BLOCK_SIZE_DEFAULT SZ_16K #define SAVE_NUM_HEADERS 2 @@ -232,6 +232,6 @@ typedef struct { }; } save_header_t; -static_assert(sizeof(save_header_t) == 0x4000, "Save header size is wrong!"); +static_assert(sizeof(save_header_t) == SZ_16K, "Save header size is wrong!"); #endif diff --git a/bdk/libs/nx_savedata/remap_storage.h b/bdk/libs/nx_savedata/remap_storage.h index 2f67e04..2917775 100644 --- a/bdk/libs/nx_savedata/remap_storage.h +++ b/bdk/libs/nx_savedata/remap_storage.h @@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define RMAP_ALIGN_SMALL 0x200 -#define RMAP_ALIGN_LARGE 0x4000 +#define RMAP_ALIGN_LARGE SZ_16K typedef struct { uint32_t magic; /* RMAP */ diff --git a/bdk/libs/nx_savedata/save_fs_list.c b/bdk/libs/nx_savedata/save_fs_list.c index 78e2abe..69cc915 100644 --- a/bdk/libs/nx_savedata/save_fs_list.c +++ b/bdk/libs/nx_savedata/save_fs_list.c @@ -250,7 +250,7 @@ uint32_t save_fs_list_allocate_entry(save_filesystem_list_ctx_t *ctx) { if (capacity == 0 || length >= capacity) { uint64_t current_size, new_size; save_allocation_table_storage_get_size(&ctx->storage, ¤t_size); - if (!save_allocation_table_storage_set_size(&ctx->storage, current_size + 0x4000)) + if (!save_allocation_table_storage_set_size(&ctx->storage, current_size + SZ_16K)) return 0; save_allocation_table_storage_get_size(&ctx->storage, &new_size); if (!save_fs_list_set_capacity(ctx, (uint32_t)(new_size / sizeof(save_fs_list_entry_t)))) diff --git a/source/keys/keys.c b/source/keys/keys.c index dd6f8e4..ae165aa 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -140,8 +140,8 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { bool have_keyblobs = true; if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { - u8 *aes_keys = (u8 *)calloc(0x1000, 1); - se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); + u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); free(aes_keys); } else { @@ -424,7 +424,7 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { } u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; - for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { + for (u32 i = SZ_32K; i < f_size(&fp); i += SZ_16K) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; if (!memcmp(keys->temp_key, read_buf, sizeof(keys->temp_key))) { @@ -493,7 +493,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); - const u32 buf_size = 0x4000; + const u32 buf_size = SZ_16K; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &rsa_keypair); @@ -639,7 +639,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl return; } - u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, 0x4000); + u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, SZ_16K); text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY(aes_kek_generation_source); @@ -816,8 +816,8 @@ static void _derive_keys() { return; } - u8 *aes_keys = (u8 *)calloc(0x1000, 1); - se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); + u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); memcpy(&dev_keys.tsec_root_key, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); memcpy(keys->tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); memcpy(&prod_keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); diff --git a/source/keys/keys.h b/source/keys/keys.h index d264851..97a9309 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -58,9 +58,9 @@ typedef struct { } ticket_record_t; typedef struct { - u8 read_buffer[0x40000]; - u8 rights_ids[0x40000 / 0x10][0x10]; - u8 titlekeys[0x40000 / 0x10][0x10]; + u8 read_buffer[SZ_256K]; + u8 rights_ids[SZ_256K / 0x10][0x10]; + u8 titlekeys[SZ_256K / 0x10][0x10]; } titlekey_buffer_t; typedef struct { From 64a6491309474f9c2422f825b854f267ae964d67 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Feb 2022 10:54:01 -0700 Subject: [PATCH 140/166] keys: Use accurate logic for eticket keypair read --- bdk/utils/util.c | 21 +++++++++++++++++++++ bdk/utils/util.h | 1 + source/keys/keys.c | 21 ++++++++++++++++++--- source/keys/keys.h | 4 +--- source/storage/nx_emmc_bis.h | 9 ++++++--- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/bdk/utils/util.c b/bdk/utils/util.c index 146c404..1fae04e 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -102,6 +102,27 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) base[ops[i].off] = ops[i].val; } +u16 crc16_calc(const u8 *buf, u32 len) +{ + const u8 *p, *q; + u16 crc = 0x55aa; + + static u16 table[16] = { + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 + }; + + q = buf + len; + for (p = buf; p < q; p++) + { + u8 oct = *p; + crc = (crc >> 4) ^ table[crc & 0xf] ^ table[(oct >> 0) & 0xf]; + crc = (crc >> 4) ^ table[crc & 0xf] ^ table[(oct >> 4) & 0xf]; + } + + return crc; +} + u32 crc32_calc(u32 crc, const u8 *buf, u32 len) { const u8 *p, *q; diff --git a/bdk/utils/util.h b/bdk/utils/util.h index d3d391f..972a906 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -83,6 +83,7 @@ u8 bit_count(u32 val); u32 bit_count_mask(u8 bits); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); +u16 crc16_calc(const u8 *buf, u32 len); u32 crc32_calc(u32 crc, const u8 *buf, u32 len); u32 get_tmr_us(); diff --git a/source/keys/keys.c b/source/keys/keys.c index ae165aa..4caa658 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -461,8 +461,23 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return false; } - // settings sysmodule manually zeroes this out below cal version 9 - u32 keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; + u32 keypair_generation = 0; + const void *eticket_device_key = NULL; + const void *eticket_iv = NULL; + + if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, 0x24E)) { + eticket_device_key = cal0->ext_ecc_rsa2048_eticket_key; + eticket_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; + + // settings sysmodule manually zeroes this out below cal version 9 + keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; + } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, 0x22E)) { + eticket_device_key = cal0->rsa2048_eticket_key; + eticket_iv = cal0->rsa2048_eticket_key_iv; + } else { + EPRINTF("Crc16 error reading device key."); + return false; + } if (keypair_generation) { keypair_generation--; @@ -478,7 +493,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit } se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), cal0->ext_ecc_rsa2048_eticket_key, sizeof(cal0->ext_ecc_rsa2048_eticket_key), cal0->ext_ecc_rsa2048_eticket_key_iv); + se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), eticket_device_key, sizeof(rsa_keypair), eticket_iv); // Check public exponent is 65537 big endian if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { diff --git a/source/keys/keys.h b/source/keys/keys.h index 97a9309..676fddb 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -67,9 +67,7 @@ typedef struct { u8 private_exponent[RSA_2048_KEY_SIZE]; u8 modulus[RSA_2048_KEY_SIZE]; u8 public_exponent[4]; - u8 reserved[0x14]; - u64 device_id; - u8 gmac[0x10]; + u8 reserved[0xC]; } rsa_keypair_t; typedef struct { diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 4eb5d82..59b766e 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -124,8 +124,10 @@ typedef struct _nx_emmc_cal0_t u8 crc16_pad20[0x10]; u8 gc_cert[0x400]; u8 gc_cert_sha256[0x20]; - u8 rsa2048_eticket_key[0x220]; - u8 crc16_pad21[0x10]; + u8 rsa2048_eticket_key_iv[0x10]; + u8 rsa2048_eticket_key[0x210]; + u8 crc16_pad21[0xE]; + u16 rsa2048_eticket_key_crc; u8 rsa2048_eticket_cert[0x240]; u8 crc16_pad22[0x10]; @@ -166,7 +168,8 @@ typedef struct _nx_emmc_cal0_t u8 ext_ecc_rsa2048_eticket_key_iv[0x10]; u8 ext_ecc_rsa2048_eticket_key[0x230]; u32 ext_ecc_rsa2048_eticket_key_ver; - u8 crc16_pad38[0xC]; + u8 crc16_pad38[0xA]; + u16 ext_ecc_rsa2048_eticket_key_crc; u8 ext_ssl_key[0x130]; u8 crc16_pad39[0x10]; u8 ext_gc_key[0x130]; From b2d970ed2a89d88b603c4dd7ad85436fa7a8a2f1 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 9 Feb 2022 13:50:17 -0700 Subject: [PATCH 141/166] keys: Fix failure to set device key for BIS deriv --- source/keys/keys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/keys/keys.c b/source/keys/keys.c index 4caa658..88520c4 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -212,6 +212,7 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { } _generate_specific_aes_key(8, keys, &keys->bis_key[0], &bis_key_sources[0], key_generation); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) + _get_device_key(8, keys, keys->temp_key, key_generation); _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2); From 514343db9b713354da43975da0df125801d93aa0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 10 Feb 2022 08:22:36 -0700 Subject: [PATCH 142/166] keys: Handle legacy ES key generation --- source/keys/key_sources.inl | 6 ++++-- source/keys/keys.c | 26 +++++++++++++++++++------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index effd947..f464db9 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -94,9 +94,9 @@ static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { // from Package1 -> Secure_Monitor static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_kek_seed_01[0x10] __attribute__((aligned(4))) = { +static const u8 aes_seal_key_mask_decrypt_device_unique_data[0x10] __attribute__((aligned(4))) = { 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_kek_seed_03[0x10] __attribute__((aligned(4))) = { +static const u8 aes_seal_key_mask_import_es_device_key[0x10] __attribute__((aligned(4))) = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; @@ -161,6 +161,8 @@ static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { 0xBE, 0xC0, 0xBC, 0x8E, 0x75, 0xA0, 0xF6, 0x0C, 0x4A, 0x56, 0x64, 0x02, 0x3E, 0xD4, 0x9C, 0xD5}; +static const u8 eticket_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { + 0x88, 0x87, 0x50, 0x90, 0xA6, 0x2F, 0x75, 0x70, 0xA2, 0xD7, 0x71, 0x51, 0xAE, 0x6D, 0x39, 0x87}; static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 88520c4..399b992 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -235,12 +235,12 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); se_aes_crypt_block_ecb(8, DECRYPT, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); se_aes_crypt_block_ecb(8, DECRYPT, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); } @@ -483,7 +483,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit if (keypair_generation) { keypair_generation--; for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; _get_device_key(7, keys, temp_device_key, keypair_generation); _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL); @@ -498,8 +498,20 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit // Check public exponent is 65537 big endian if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { - EPRINTF("Invalid public exponent."); - return false; + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; + _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); + se_aes_crypt_block_ecb(8, DECRYPT, keys->temp_key, eticket_rsa_kek_source_legacy); + + se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); + se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), eticket_device_key, sizeof(rsa_keypair), eticket_iv); + + if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { + EPRINTF("Invalid public exponent."); + return false; + } else { + memcpy(keys->eticket_rsa_kek, keys->temp_key, sizeof(keys->eticket_rsa_kek)); + } } if (!_test_key_pair(rsa_keypair.public_exponent, rsa_keypair.private_exponent, rsa_keypair.modulus)) { @@ -702,10 +714,10 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(per_console_key_source); SAVE_KEY(retail_specific_aes_key_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; SAVE_KEY_VAR(rsa_oaep_kek_generation_source, keys->temp_key); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; SAVE_KEY_VAR(rsa_private_kek_generation_source, keys->temp_key); SAVE_KEY(save_mac_kek_source); SAVE_KEY_VAR(save_mac_key, keys->save_mac_key); From 54412f5a9d9bf68c1aa9508cc24bc477a34950aa Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 10 Feb 2022 08:45:06 -0700 Subject: [PATCH 143/166] keys: Add helper func for eticket rsa kek --- source/keys/keys.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index 399b992..74d2ecf 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -73,7 +73,7 @@ static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed); static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation); static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision); // titlekey functions @@ -226,6 +226,14 @@ static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { } } +static void _derive_eticket_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *master_key, const void *kek_source) { + u8 kek_seed[AES_128_KEY_SIZE]; + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + kek_seed[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; + _generate_kek(ks, eticket_rsa_kekek_source, master_key, kek_seed, NULL); + se_aes_crypt_block_ecb(ks, DECRYPT, out_rsa_kek, kek_source); +} + static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { _get_device_key(8, keys, keys->temp_key, 0); @@ -234,10 +242,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { } if (_key_exists(keys->master_key[0])) { - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; - _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); + _derive_eticket_rsa_kek(keys, 8, keys->eticket_rsa_kek, keys->master_key[0], is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; @@ -440,7 +445,7 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { return true; } -static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { +static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { if (!_key_exists(keys->eticket_rsa_kek)) { return false; } @@ -482,12 +487,8 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit if (keypair_generation) { keypair_generation--; - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; - u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0}; - _get_device_key(7, keys, temp_device_key, keypair_generation); - _generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL); - se_aes_crypt_block_ecb(7, DECRYPT, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source); + _get_device_key(7, keys, keys->temp_key, keypair_generation); + _derive_eticket_rsa_kek(keys, 7, keys->eticket_rsa_kek_personalized, keys->temp_key, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key)); } else { memcpy(keys->temp_key, keys->eticket_rsa_kek, sizeof(keys->temp_key)); @@ -498,10 +499,8 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit // Check public exponent is 65537 big endian if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; - _generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, keys->temp_key, eticket_rsa_kek_source_legacy); + // try legacy kek source + _derive_eticket_rsa_kek(keys, 7, keys->temp_key, keys->master_key[0], eticket_rsa_kek_source_legacy); se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), eticket_device_key, sizeof(rsa_keypair), eticket_iv); @@ -530,7 +529,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return true; } -static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { +static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { // Set BIS keys. // PRODINFO/PRODINFOF se_aes_key_set(0, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); @@ -571,7 +570,7 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit EPRINTF("Unable to get SD seed."); } - bool res = _derive_titlekeys(keys, titlekey_buffer); + bool res = _derive_titlekeys(keys, titlekey_buffer, is_dev); if (!res) { EPRINTF("Unable to derive titlekeys."); } @@ -882,7 +881,7 @@ static void _derive_keys() { if (!emmc_storage.initialized) { EPRINTF("eMMC not initialized.\nSkipping SD seed and titlekeys."); } else if (_key_exists(keys->bis_key[2])) { - _derive_emmc_keys(keys, titlekey_buffer); + _derive_emmc_keys(keys, titlekey_buffer, is_dev); } else { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); } @@ -963,7 +962,7 @@ static void _save_key_family(const char *name, const void *data, u32 start_key, free(temp_name); } -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) { +static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed) { if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) return; From 61c1dad57988e976e8ec68eacdba12ae3aac327d Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 21 Mar 2022 19:03:17 -0600 Subject: [PATCH 144/166] Support 14.0.0 keys --- source/hos/hos.h | 3 ++- source/keys/key_sources.inl | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/hos/hos.h b/source/hos/hos.h index 4ff6bd8..b4111c7 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -33,6 +33,7 @@ #define KB_FIRMWARE_VERSION_910 10 #define KB_FIRMWARE_VERSION_1210 11 #define KB_FIRMWARE_VERSION_1300 12 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1300 //!TODO: Update on mkey changes. +#define KB_FIRMWARE_VERSION_1400 13 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1400 //!TODO: Update on mkey changes. #endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index f464db9..9bfdbb0 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -37,6 +37,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 {0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0 {0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0 + {0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81}, //14.0.0 }; //!TODO: Update on mkey changes. @@ -54,6 +55,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ {0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */ + {0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38}, /* Master key 0C encrypted with Master key 0D. */ }; //!TODO: Update on mkey changes. @@ -71,6 +73,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr {0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */ {0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C}, /* Master key 0A encrypted with Master key 0B. */ {0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */ + {0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12}, /* Master key 0C encrypted with Master key 0D. */ }; static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { @@ -131,6 +134,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0. {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. {0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6}, // 13.0.0. + {0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A}, // 14.0.0. }; //!TODO: Update on mkey changes. static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. @@ -141,6 +145,7 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE}, // 9.1.0. {0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0. {0x4D, 0x5A, 0xB2, 0xC9, 0xE9, 0xE4, 0x4E, 0xA4, 0xD3, 0xBF, 0x94, 0x12, 0x36, 0x30, 0xD0, 0x7F}, // 13.0.0. + {0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87}, // 14.0.0. }; //!TODO: Update on mkey changes. static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -154,6 +159,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ + {0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D}, /* 14.0.0 Device Master Key Source Source. */ }; //!TODO: Update on mkey changes. // from ES @@ -183,6 +189,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ + {0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2}, /* 14.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -196,6 +203,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ + {0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA}, /* 14.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. // from SPL From c704d0a6e6bbb823169f636102e371b09f47155f Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 21 Mar 2022 19:03:56 -0600 Subject: [PATCH 145/166] Bump version to v1.9.7 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 2c846cb..539334e 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,5 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 6 +LPVERSION_BUGFX := 7 LPVERSION_RSVD := 0 From 582bc916053ab2f30aeb78d7932232a5bbd78bd5 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 31 Mar 2022 12:28:32 -0600 Subject: [PATCH 146/166] Move Mariko partial key dump to main menu --- source/gfx/tui.c | 2 +- source/gfx/tui.h | 4 +-- source/keys/keys.c | 36 ++++++++++--------- source/keys/keys.h | 1 + source/main.c | 90 +++++++++++++++++++++++++++++++++++----------- 5 files changed, 92 insertions(+), 41 deletions(-) diff --git a/source/gfx/tui.c b/source/gfx/tui.c index 6d0e6b4..ec6c08a 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -135,7 +135,7 @@ void *tui_do_menu(menu_t *menu) gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); else gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); - if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) + if (menu->ents[cnt].type != MENT_CHGLINE) { if (cnt == idx) gfx_printf(" %s", menu->ents[cnt].caption); diff --git a/source/gfx/tui.h b/source/gfx/tui.h index 6f02781..98330b6 100644 --- a/source/gfx/tui.h +++ b/source/gfx/tui.h @@ -54,8 +54,8 @@ typedef struct _menu_t #define MDEF_END() {MENT_END} #define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } } #define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } } -#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } } -#define MDEF_BACK() { MENT_BACK, "Back" } +#define MDEF_MENU(caption, _menu, color) { MENT_MENU, caption, color, NULL, { .menu = _menu } } +#define MDEF_BACK(color) { MENT_BACK, "Back", color } #define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color } #define MDEF_CHGLINE() {MENT_CHGLINE} diff --git a/source/keys/keys.c b/source/keys/keys.c index 74d2ecf..c5c4bae 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -583,11 +583,15 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit // The security engine supports partial key override for locked keyslots // This allows for a manageable brute force on a PC // Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered -static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { +int save_mariko_partial_keys(u32 start, u32 count, bool append) { if (start + count > SE_AES_KEYSLOT_COUNT) { - return; + return 1; } + display_backlight_brightness(h_cfg.backlight, 1000); + gfx_clear_partial_grey(0x1B, 32, 1224); + gfx_con_setpos(0, 32); + u32 pos = 0; u32 zeros[AES_128_KEY_SIZE / 4] = {0}; u8 *data = malloc(4 * AES_128_KEY_SIZE); @@ -632,11 +636,11 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { if (strlen(text_buffer) == 0) { EPRINTFARGS("Failed to dump partial keys %d-%d.", start, start + count - 1); - return; + free(text_buffer); + return 2; } FIL fp; - u32 res = 0; BYTE mode = FA_WRITE; if (append) { @@ -645,10 +649,16 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { mode |= FA_CREATE_ALWAYS; } - res = f_open(&fp, "sd:/switch/partialaes.keys", mode); - if (res) { + if (!sd_mount()) { + EPRINTF("Unable to mount SD."); + free(text_buffer); + return 3; + } + + if (f_open(&fp, "sd:/switch/partialaes.keys", mode)) { EPRINTF("Unable to write partial keys to SD."); - return; + free(text_buffer); + return 3; } f_write(&fp, text_buffer, strlen(text_buffer), NULL); @@ -657,6 +667,8 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]); free(text_buffer); + + return 0; } static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { @@ -756,10 +768,6 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl } else EPRINTF("Unable to save keys to SD."); - if (h_cfg.t210b01) { - _save_mariko_partial_keys(12, 4, true); - } - if (_titlekey_count == 0 || !titlekey_buffer) { free(text_buffer); return; @@ -801,12 +809,6 @@ static void _derive_keys() { minerva_periodic_training(); - if (h_cfg.t210b01) { - _save_mariko_partial_keys(0, 12, false); - } - - minerva_periodic_training(); - if (!_check_keyslot_access()) { EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip."); return; diff --git a/source/keys/keys.h b/source/keys/keys.h index 676fddb..8e2fb23 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -141,5 +141,6 @@ typedef struct { #define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, ARRAY_SIZE(varname), sizeof(*(varname)), text_buffer) void dump_keys(); +int save_mariko_partial_keys(u32 start, u32 count, bool append); #endif diff --git a/source/main.c b/source/main.c index cd8e92e..b4aa670 100644 --- a/source/main.c +++ b/source/main.c @@ -304,26 +304,80 @@ void dump_emunand() dump_keys(); } +void dump_mariko_partial_keys(); + +ment_t ment_partials[] = { + MDEF_BACK(colors[0]), + MDEF_CHGLINE(), + MDEF_CAPTION("This dumps the results of writing zeros", colors[1]), + MDEF_CAPTION("over consecutive 32-bit portions of each", colors[1]), + MDEF_CAPTION("keyslot, the results of which can then", colors[1]), + MDEF_CAPTION("be bruteforced quickly on a computer", colors[1]), + MDEF_CAPTION("to recover keys from unreadable keyslots.", colors[1]), + MDEF_CHGLINE(), + MDEF_CAPTION("This includes the Mariko KEK and BEK", colors[2]), + MDEF_CAPTION("as well as the unique SBK.", colors[2]), + MDEF_CHGLINE(), + MDEF_CAPTION("These are not useful for most users", colors[3]), + MDEF_CAPTION("but are included for archival purposes.", colors[3]), + MDEF_CHGLINE(), + MDEF_CAPTION("Warning: this wipes keyslots!", colors[4]), + MDEF_CAPTION("The console must be completely restarted!", colors[4]), + MDEF_CAPTION("Modchip must run again to fix the keys!", colors[4]), + MDEF_CAPTION("---------------", colors[5]), + MDEF_HANDLER("Dump Mariko Partials", dump_mariko_partial_keys, colors[0]), + MDEF_END() +}; + +menu_t menu_partials = { ment_partials, NULL, 0, 0 }; + power_state_t STATE_POWER_OFF = POWER_OFF_RESET; power_state_t STATE_REBOOT_FULL = POWER_OFF_REBOOT; power_state_t STATE_REBOOT_RCM = REBOOT_RCM; power_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES; ment_t ment_top[] = { - MDEF_HANDLER("Dump from SysNAND", dump_sysnand, COLOR_RED), - MDEF_HANDLER("Dump from EmuNAND", dump_emunand, COLOR_ORANGE), - MDEF_CAPTION("---------------", COLOR_YELLOW), - MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), - MDEF_HANDLER("Reboot to hekate", launch_hekate, COLOR_BLUE), - MDEF_CAPTION("---------------", COLOR_VIOLET), - MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_RED), - MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_ORANGE), - MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_YELLOW), + MDEF_HANDLER("Dump from SysNAND", dump_sysnand, colors[0]), + MDEF_HANDLER("Dump from EmuNAND", dump_emunand, colors[1]), + MDEF_CAPTION("---------------", colors[2]), + MDEF_MENU("Dump Mariko Partials (requires reboot)", &menu_partials, colors[3]), + MDEF_CAPTION("---------------", colors[4]), + MDEF_HANDLER("Payloads...", launch_tools, colors[5]), + MDEF_HANDLER("Reboot to hekate", launch_hekate, colors[0]), + MDEF_CAPTION("---------------", colors[1]), + MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, colors[2]), + MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, colors[3]), + MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, colors[4]), MDEF_END() }; menu_t menu_top = { ment_top, NULL, 0, 0 }; +void grey_out_menu_item(ment_t *menu) +{ + menu->type = MENT_CAPTION; + menu->color = 0xFF555555; + menu->handler = NULL; +} + +void dump_mariko_partial_keys() +{ + if (h_cfg.t210b01) { + int res = save_mariko_partial_keys(0, 16, false); + if (res == 0 || res == 3) + { + // Grey out dumping menu items as the keyslots have been invalidated. + grey_out_menu_item(&ment_top[0]); + grey_out_menu_item(&ment_top[1]); + grey_out_menu_item(&ment_top[3]); + grey_out_menu_item(&ment_partials[18]); + } + + gfx_printf("\n%kPress a button to return to the menu.", COLOR_ORANGE); + btn_wait(); + } +} + extern void pivot_stack(u32 stack_top); void ipl_main() @@ -373,30 +427,24 @@ void ipl_main() // Grey out emummc option if not present. if (h_cfg.emummc_force_disable) { - ment_top[1].type = MENT_CAPTION; - ment_top[1].color = 0xFF555555; - ment_top[1].handler = NULL; + grey_out_menu_item(&ment_top[1]); } // Grey out reboot to RCM option if on Mariko or patched console. if (h_cfg.t210b01 || h_cfg.rcm_patched) { - ment_top[7].type = MENT_CAPTION; - ment_top[7].color = 0xFF555555; - ment_top[7].handler = NULL; + grey_out_menu_item(&ment_top[9]); } - if (h_cfg.rcm_patched) - { - ment_top[7].data = &STATE_REBOOT_FULL; + // Grey out Mariko partial dump option on Erista. + if (!h_cfg.t210b01) { + grey_out_menu_item(&ment_top[3]); } // Grey out reboot to hekate option if no update.bin found. if (f_stat("bootloader/update.bin", NULL)) { - ment_top[4].type = MENT_CAPTION; - ment_top[4].color = 0xFF555555; - ment_top[4].handler = NULL; + grey_out_menu_item(&ment_top[6]); } minerva_change_freq(FREQ_800); From 5f35c8396da14f23b076f140364647273063fe69 Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 31 Mar 2022 13:58:26 -0600 Subject: [PATCH 147/166] keys: Move master key derivation into own function --- source/keys/keys.c | 53 +++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index c5c4bae..43702ff 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -802,6 +802,34 @@ static bool _check_keyslot_access() { return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; } +static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_ctx_t *dev_keys, bool is_dev) { + key_derivation_ctx_t *keys = is_dev ? dev_keys : prod_keys; + + if (h_cfg.t210b01) { + _derive_master_key_mariko(keys, is_dev); + minerva_periodic_training(); + _derive_master_keys_from_latest_key(keys, is_dev); + } else { + int res = _run_ams_keygen(keys); + if (res) { + return; + } + + u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); + memcpy(&dev_keys->tsec_root_key, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(keys->tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&prod_keys->tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + free(aes_keys); + + _derive_master_keys_from_latest_key(prod_keys, false); + minerva_periodic_training(); + _derive_master_keys_from_latest_key(dev_keys, true); + minerva_periodic_training(); + _derive_keyblob_keys(keys); + } +} + static void _derive_keys() { if (!f_stat("sd:/switch/partialaes.keys", NULL)) { f_unlink("sd:/switch/partialaes.keys"); @@ -834,30 +862,7 @@ static void _derive_keys() { key_derivation_ctx_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; key_derivation_ctx_t *keys = is_dev ? &dev_keys : &prod_keys; - // Master key derivation - if (h_cfg.t210b01) { - _derive_master_key_mariko(keys, is_dev); - minerva_periodic_training(); - _derive_master_keys_from_latest_key(keys, is_dev); - } else { - int res = _run_ams_keygen(keys); - if (res) { - return; - } - - u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); - se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); - memcpy(&dev_keys.tsec_root_key, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(keys->tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(&prod_keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - free(aes_keys); - - _derive_master_keys_from_latest_key(&prod_keys, false); - minerva_periodic_training(); - _derive_master_keys_from_latest_key(&dev_keys, true); - minerva_periodic_training(); - _derive_keyblob_keys(keys); - } + _derive_master_keys(&prod_keys, &dev_keys, is_dev); TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); From 065ba8bc115772c99496d41454f17e4ff1f18b7e Mon Sep 17 00:00:00 2001 From: shchmue Date: Thu, 31 Mar 2022 18:30:57 -0600 Subject: [PATCH 148/166] Add Amiibo key dump support --- source/keys/key_sources.inl | 30 +++++++++ source/keys/keys.c | 125 ++++++++++++++++++++++++++++++++---- source/keys/keys.h | 22 +++++++ source/main.c | 30 +++++---- 4 files changed, 182 insertions(+), 25 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 9bfdbb0..02063b2 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -209,6 +209,8 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW // from SPL static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; +static const u8 aes_key_decryption_source[0x10] __attribute__((aligned(4))) = { + 0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}; // from FS static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { @@ -250,3 +252,31 @@ static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = { static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = { 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; + +// from NFC +static const u8 nfc_key_source[0x10] __attribute__((aligned(4))) = { + 0x83, 0xF6, 0xEF, 0xD8, 0x13, 0x26, 0x49, 0xAB, 0x97, 0x5F, 0xEA, 0xBA, 0x65, 0x71, 0xCA, 0xCA}; +static const u8 encrypted_nfc_keys[0x80] __attribute__((aligned(4))) = { + 0x76, 0x50, 0x87, 0x02, 0x40, 0xA6, 0x5A, 0x98, 0xCE, 0x39, 0x2F, 0xC8, 0x83, 0xAF, 0x54, 0x76, + 0x28, 0xFF, 0x50, 0xFC, 0xC1, 0xFB, 0x26, 0x14, 0xA2, 0x4A, 0xA6, 0x74, 0x90, 0xA4, 0x37, 0x06, + 0x03, 0x63, 0xC2, 0xB1, 0xAF, 0x9F, 0xF7, 0x07, 0xFC, 0x8A, 0xB9, 0xCA, 0x28, 0x68, 0x6E, 0xF7, + 0x42, 0xCD, 0x68, 0x13, 0xCD, 0x7B, 0x3A, 0x60, 0x3E, 0x8B, 0xAB, 0x3A, 0xCC, 0xED, 0xE0, 0xDD, + 0x71, 0x1F, 0xA5, 0xDE, 0xB8, 0xB1, 0xF5, 0x1D, 0x14, 0x73, 0xBE, 0x27, 0xCC, 0xA1, 0x9B, 0x23, + 0x06, 0x91, 0x89, 0x05, 0xED, 0xD6, 0x92, 0x76, 0x3F, 0x42, 0xFB, 0xD1, 0x8F, 0x2D, 0x6D, 0x72, + 0xC8, 0x9E, 0x48, 0xE8, 0x03, 0x64, 0xF0, 0x3C, 0x0E, 0x2A, 0xF1, 0x26, 0x83, 0x02, 0x4F, 0xE2, + 0x41, 0xAA, 0xC8, 0x33, 0x68, 0x84, 0x3A, 0xFB, 0x87, 0x18, 0xEA, 0xF7, 0x36, 0xA2, 0x4E, 0xA9}; +static const u8 encrypted_nfc_keys_dev[0x80] __attribute__((aligned(4))) = { + 0x13, 0xB0, 0xFB, 0xC2, 0x91, 0x6D, 0x6E, 0x5A, 0x10, 0x31, 0x40, 0xB7, 0xDF, 0xCF, 0x69, 0x69, + 0xB0, 0xFA, 0xAE, 0x7F, 0xB2, 0x4D, 0x27, 0xC9, 0xE9, 0x3F, 0x5B, 0x38, 0x39, 0x24, 0x98, 0xCE, + 0xED, 0xD2, 0xA9, 0x6C, 0x6F, 0xA7, 0x72, 0xD7, 0x11, 0x31, 0x17, 0x93, 0x12, 0x49, 0x32, 0x85, + 0x21, 0xE5, 0xE1, 0x88, 0x0F, 0x08, 0xF2, 0x30, 0x5C, 0xC3, 0xAA, 0xFF, 0xC0, 0xAB, 0x21, 0x96, + 0x74, 0x39, 0xED, 0xE0, 0x5A, 0xB6, 0x75, 0xC2, 0x3B, 0x08, 0x61, 0xE4, 0xA7, 0xD6, 0xED, 0x8C, + 0xA9, 0x02, 0x12, 0xA6, 0xCC, 0x27, 0x4C, 0x1C, 0x41, 0x9C, 0xD8, 0x4C, 0x00, 0xC7, 0x5B, 0x5D, + 0xED, 0xC2, 0x3D, 0x5E, 0x00, 0xF5, 0x49, 0xFA, 0x6C, 0x75, 0x67, 0xCF, 0x1F, 0x73, 0x1A, 0xE8, + 0x47, 0xD4, 0x3D, 0x9B, 0x83, 0x5B, 0x18, 0x2F, 0x95, 0xA9, 0x04, 0xBC, 0x2E, 0xBB, 0x64, 0x4A}; +static const u8 nfc_blob_hash[0x20] __attribute__((aligned(4))) = { + 0x7F, 0x92, 0x83, 0x65, 0x4E, 0xC1, 0x09, 0x7F, 0xBD, 0xFF, 0x31, 0xDE, 0x94, 0x66, 0x51, 0xAE, + 0x60, 0xC2, 0x85, 0x4A, 0xFB, 0x54, 0x4A, 0xBE, 0x89, 0x63, 0xD3, 0x89, 0x63, 0x9C, 0x71, 0x0E}; +static const u8 nfc_blob_hash_dev[0x20] __attribute__((aligned(4))) = { + 0x4E, 0x36, 0x59, 0x1C, 0x75, 0x80, 0x23, 0x03, 0x98, 0x2D, 0x45, 0xD9, 0x85, 0xB8, 0x60, 0x18, + 0x7C, 0x85, 0x37, 0x9B, 0xCB, 0xBA, 0xF3, 0xDC, 0x25, 0x38, 0x73, 0xDB, 0x2F, 0xFA, 0xAE, 0x26}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 43702ff..f17a66d 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -74,6 +74,7 @@ static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x0 static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed); +static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key); static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation); static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision); // titlekey functions @@ -584,6 +585,11 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit // This allows for a manageable brute force on a PC // Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered int save_mariko_partial_keys(u32 start, u32 count, bool append) { + const char *keyfile_path = "sd:/switch/partialaes.keys"; + if (!f_stat(keyfile_path, NULL)) { + f_unlink(keyfile_path); + } + if (start + count > SE_AES_KEYSLOT_COUNT) { return 1; } @@ -592,6 +598,8 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { gfx_clear_partial_grey(0x1B, 32, 1224); gfx_con_setpos(0, 32); + color_idx = 0; + u32 pos = 0; u32 zeros[AES_128_KEY_SIZE / 4] = {0}; u8 *data = malloc(4 * AES_128_KEY_SIZE); @@ -655,7 +663,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { return 3; } - if (f_open(&fp, "sd:/switch/partialaes.keys", mode)) { + if (f_open(&fp, keyfile_path, mode)) { EPRINTF("Unable to write partial keys to SD."); free(text_buffer); return 3; @@ -664,7 +672,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { f_write(&fp, text_buffer, strlen(text_buffer), NULL); f_close(&fp); - gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]); + gfx_printf("%kWrote partials to %s\n", colors[(color_idx++) % 6], keyfile_path); free(text_buffer); @@ -757,16 +765,15 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX); f_mkdir("sd:/switch"); - char keyfile_path[30] = "sd:/switch/prod.keys"; - if (is_dev) { - s_printf(&keyfile_path[11], "dev.keys"); - } + + const char *keyfile_path = is_dev ? "sd:/switch/dev.keys" : "sd:/switch/prod.keys"; FILINFO fno; if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); - } else + } else { EPRINTF("Unable to save keys to SD."); + } if (_titlekey_count == 0 || !titlekey_buffer) { free(text_buffer); @@ -784,11 +791,13 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl s_printf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); s_printf(titlekey_text[i].newline, "\n"); } - s_printf(&keyfile_path[11], "title.keys"); + + keyfile_path = "sd:/switch/title.keys"; if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); - } else + } else { EPRINTF("Unable to save titlekeys to SD."); + } free(text_buffer); } @@ -831,10 +840,6 @@ static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_ } static void _derive_keys() { - if (!f_stat("sd:/switch/partialaes.keys", NULL)) { - f_unlink("sd:/switch/partialaes.keys"); - } - minerva_periodic_training(); if (!_check_keyslot_access()) { @@ -875,10 +880,13 @@ static void _derive_keys() { minerva_periodic_training(); _derive_non_unique_keys(&prod_keys, is_dev); + minerva_periodic_training(); _derive_non_unique_keys(&dev_keys, is_dev); + minerva_periodic_training(); _derive_per_generation_keys(&prod_keys); + minerva_periodic_training(); _derive_per_generation_keys(&dev_keys); @@ -907,6 +915,89 @@ static void _derive_keys() { } } +void derive_amiibo_keys() { + minerva_change_freq(FREQ_1600); + + bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; + + key_derivation_ctx_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; + key_derivation_ctx_t *keys = is_dev ? &dev_keys : &prod_keys; + const u8 *encrypted_keys = is_dev ? encrypted_nfc_keys_dev : encrypted_nfc_keys; + + _derive_master_keys(&prod_keys, &dev_keys, is_dev); + + minerva_periodic_training(); + + display_backlight_brightness(h_cfg.backlight, 1000); + gfx_clear_partial_grey(0x1B, 32, 1224); + gfx_con_setpos(0, 32); + + color_idx = 0; + + minerva_periodic_training(); + + if (!_key_exists(keys->master_key[0])) { + EPRINTF("Unable to derive master keys for NFC."); + minerva_change_freq(FREQ_800); + btn_wait(); + return; + } + + _decrypt_aes_key(8, keys->temp_key, nfc_key_source, keys->master_key[0]); + + nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; + static const u8 nfc_iv[AES_128_KEY_SIZE] = { + 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; + se_aes_key_set(6, keys->temp_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(6, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); + + minerva_periodic_training(); + + u8 xor_pad[0x20] __attribute__((aligned(4))) = {0}; + se_aes_key_set(6, nfc_keyblob.ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(6, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); + + minerva_periodic_training(); + + nfc_save_key_t __attribute__((aligned(4))) nfc_save_keys[2] = {0}; + memcpy(nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key)); + memcpy(nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase)); + nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed); + memcpy(nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed)); + memcpy(nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad)); + + memcpy(nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif)); + memcpy(nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif)); + nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif); + memcpy(nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif)); + memcpy(nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad)); + + minerva_periodic_training(); + + u8 hash[0x20] = {0}; + se_calc_sha256_oneshot(hash, &nfc_save_keys[0], sizeof(nfc_save_keys)); + + if (memcmp(hash, is_dev ? nfc_blob_hash_dev : nfc_blob_hash, sizeof(hash)) != 0) { + EPRINTF("Amiibo hash mismatch. Skipping save."); + minerva_change_freq(FREQ_800); + btn_wait(); + return; + } + + const char *keyfile_path = is_dev ? "sd:/switch/key_dev.bin" : "sd:/switch/key_retail.bin"; + + if (!sd_save_to_file(&nfc_save_keys[0], sizeof(nfc_save_keys), keyfile_path)) { + gfx_printf("%kWrote Amiibo keys to\n %s\n", colors[(color_idx++) % 6], keyfile_path); + } else { + EPRINTF("Unable to save Amiibo keys to SD."); + } + + gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx++) % 6]); + minerva_change_freq(FREQ_800); + btn_wait(); + gfx_clear_grey(0x1B); +} + void dump_keys() { minerva_change_freq(FREQ_1600); @@ -969,6 +1060,8 @@ static void _save_key_family(const char *name, const void *data, u32 start_key, free(temp_name); } +// Equivalent to spl::GenerateAesKek. When key_seed is set, the result is as if spl::GenerateAesKey was called immediately after. +// The generation and option args are dictated by master_key and kek_seed. static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed) { if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) return; @@ -980,6 +1073,12 @@ static void _generate_kek(u32 ks, const void *key_source, const void *master_key se_aes_unwrap_key(ks, ks, key_seed); } +// Equivalent to spl::DecryptAesKey. +static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key) { + _generate_kek(ks, aes_key_decryption_source, master_key, aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(ks, 0, dst, key_source); +} + static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) { se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE); u8 *d = (u8 *)dst; diff --git a/source/keys/keys.h b/source/keys/keys.h index 8e2fb23..ccb1e66 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -83,6 +83,27 @@ typedef struct { u8 unused[0x150]; } encrypted_keyblob_t; +typedef struct { + char phrase[0xE]; + u8 seed[0xE]; + u8 hmac_key[0x10]; + char phrase_for_verif[0xE]; + u8 seed_for_verif[0x10]; + u8 hmac_key_for_verif[0x10]; + u8 ctr_key[0x10]; + u8 ctr_iv[0x10]; + u8 pad[6]; +} nfc_keyblob_t; + +typedef struct { + u8 hmac_key[0x10]; + char phrase[0xE]; + u8 rsvd; + u8 seed_size; + u8 seed[0x10]; + u8 xor_pad[0x20]; +} nfc_save_key_t; + typedef struct { u8 temp_key[AES_128_KEY_SIZE], bis_key[4][AES_128_KEY_SIZE * 2], @@ -142,5 +163,6 @@ typedef struct { void dump_keys(); int save_mariko_partial_keys(u32 start, u32 count, bool append); +void derive_amiibo_keys(); #endif diff --git a/source/main.c b/source/main.c index b4aa670..368b820 100644 --- a/source/main.c +++ b/source/main.c @@ -304,6 +304,11 @@ void dump_emunand() dump_keys(); } +void dump_amiibo_keys() +{ + derive_amiibo_keys(); +} + void dump_mariko_partial_keys(); ment_t ment_partials[] = { @@ -340,14 +345,15 @@ ment_t ment_top[] = { MDEF_HANDLER("Dump from SysNAND", dump_sysnand, colors[0]), MDEF_HANDLER("Dump from EmuNAND", dump_emunand, colors[1]), MDEF_CAPTION("---------------", colors[2]), - MDEF_MENU("Dump Mariko Partials (requires reboot)", &menu_partials, colors[3]), - MDEF_CAPTION("---------------", colors[4]), - MDEF_HANDLER("Payloads...", launch_tools, colors[5]), - MDEF_HANDLER("Reboot to hekate", launch_hekate, colors[0]), - MDEF_CAPTION("---------------", colors[1]), - MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, colors[2]), - MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, colors[3]), - MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, colors[4]), + MDEF_HANDLER("Dump Amiibo Keys", dump_amiibo_keys, colors[3]), + MDEF_MENU("Dump Mariko Partials (requires reboot)", &menu_partials, colors[4]), + MDEF_CAPTION("---------------", colors[5]), + MDEF_HANDLER("Payloads...", launch_tools, colors[0]), + MDEF_HANDLER("Reboot to hekate", launch_hekate, colors[1]), + MDEF_CAPTION("---------------", colors[2]), + MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, colors[3]), + MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, colors[4]), + MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, colors[5]), MDEF_END() }; @@ -369,7 +375,7 @@ void dump_mariko_partial_keys() // Grey out dumping menu items as the keyslots have been invalidated. grey_out_menu_item(&ment_top[0]); grey_out_menu_item(&ment_top[1]); - grey_out_menu_item(&ment_top[3]); + grey_out_menu_item(&ment_top[4]); grey_out_menu_item(&ment_partials[18]); } @@ -433,18 +439,18 @@ void ipl_main() // Grey out reboot to RCM option if on Mariko or patched console. if (h_cfg.t210b01 || h_cfg.rcm_patched) { - grey_out_menu_item(&ment_top[9]); + grey_out_menu_item(&ment_top[10]); } // Grey out Mariko partial dump option on Erista. if (!h_cfg.t210b01) { - grey_out_menu_item(&ment_top[3]); + grey_out_menu_item(&ment_top[4]); } // Grey out reboot to hekate option if no update.bin found. if (f_stat("bootloader/update.bin", NULL)) { - grey_out_menu_item(&ment_top[6]); + grey_out_menu_item(&ment_top[7]); } minerva_change_freq(FREQ_800); From 85e56adbf5659a09a0c6e769d2d6898f94f09770 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 2 Apr 2022 09:45:14 -0600 Subject: [PATCH 149/166] keys: Add ETicket RSA keypair to keyfile --- source/keys/keys.c | 19 ++++++++++--------- source/keys/keys.h | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index f17a66d..0b325f1 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -453,8 +453,6 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - rsa_keypair_t rsa_keypair = {0}; - if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { EPRINTF("Unable to read PRODINFO."); return false; @@ -496,34 +494,36 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit } se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), eticket_device_key, sizeof(rsa_keypair), eticket_iv); + se_aes_crypt_ctr(6, &keys->rsa_keypair, sizeof(keys->rsa_keypair), eticket_device_key, sizeof(keys->rsa_keypair), eticket_iv); // Check public exponent is 65537 big endian - if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { + if (_read_be_u32(keys->rsa_keypair.public_exponent, 0) != 65537) { // try legacy kek source _derive_eticket_rsa_kek(keys, 7, keys->temp_key, keys->master_key[0], eticket_rsa_kek_source_legacy); se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &rsa_keypair, sizeof(rsa_keypair), eticket_device_key, sizeof(rsa_keypair), eticket_iv); + se_aes_crypt_ctr(6, &keys->rsa_keypair, sizeof(keys->rsa_keypair), eticket_device_key, sizeof(keys->rsa_keypair), eticket_iv); - if (_read_be_u32(rsa_keypair.public_exponent, 0) != 65537) { + if (_read_be_u32(keys->rsa_keypair.public_exponent, 0) != 65537) { EPRINTF("Invalid public exponent."); + memset(&keys->rsa_keypair, 0, sizeof(keys->rsa_keypair)); return false; } else { memcpy(keys->eticket_rsa_kek, keys->temp_key, sizeof(keys->eticket_rsa_kek)); } } - if (!_test_key_pair(rsa_keypair.public_exponent, rsa_keypair.private_exponent, rsa_keypair.modulus)) { + if (!_test_key_pair(keys->rsa_keypair.public_exponent, keys->rsa_keypair.private_exponent, keys->rsa_keypair.modulus)) { EPRINTF("Invalid keypair. Check eticket_rsa_kek."); + memset(&keys->rsa_keypair, 0, sizeof(keys->rsa_keypair)); return false; } - se_rsa_key_set(0, rsa_keypair.modulus, sizeof(rsa_keypair.modulus), rsa_keypair.private_exponent, sizeof(rsa_keypair.private_exponent)); + se_rsa_key_set(0, keys->rsa_keypair.modulus, sizeof(keys->rsa_keypair.modulus), keys->rsa_keypair.private_exponent, sizeof(keys->rsa_keypair.private_exponent)); const u32 buf_size = SZ_16K; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); - _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &rsa_keypair); + _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &keys->rsa_keypair); gfx_printf("\n%k Found %d titlekeys.\n\n", colors[(color_idx++) % 6], _titlekey_count); @@ -704,6 +704,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(eticket_rsa_kek_source); } SAVE_KEY(eticket_rsa_kekek_source); + _save_key("eticket_rsa_keypair", &keys->rsa_keypair, sizeof(keys->rsa_keypair), text_buffer); SAVE_KEY(header_kek_source); SAVE_KEY_VAR(header_key, keys->header_key); SAVE_KEY(header_key_source); diff --git a/source/keys/keys.h b/source/keys/keys.h index ccb1e66..0d65681 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -131,6 +131,7 @@ typedef struct { tsec_root_key[AES_128_KEY_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; + rsa_keypair_t rsa_keypair; } key_derivation_ctx_t; typedef struct { From 815bb55f6479b15cee8eea5cf32c510cc6e0cd3b Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 2 Apr 2022 09:47:29 -0600 Subject: [PATCH 150/166] Bump version to v1.9.8 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index 539334e..eafbd19 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,5 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 7 +LPVERSION_BUGFX := 8 LPVERSION_RSVD := 0 From 58eb5f6dd2a6c27a7efa6628f4eaefc4d89e0fea Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 18 May 2022 08:09:52 -0600 Subject: [PATCH 151/166] Suport personalized SSL kek, dump SSL private key --- source/keys/key_sources.inl | 8 +++ source/keys/keys.c | 97 ++++++++++++++++++++++++++++++------ source/keys/keys.h | 2 + source/storage/nx_emmc_bis.h | 13 +++-- 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 02063b2..ef2f044 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -101,6 +101,8 @@ static const u8 aes_seal_key_mask_decrypt_device_unique_data[0x10] __attribute__ 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; static const u8 aes_seal_key_mask_import_es_device_key[0x10] __attribute__((aligned(4))) = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; +static const u8 aes_seal_key_mask_decrypt_ssl_client_cert_key[0x10] __attribute__((aligned(4))) = { + 0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75}; static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { @@ -177,6 +179,12 @@ static const u8 ssl_rsa_kek_source_x[0x10] __attribute__((aligned(4))) = { 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; static const u8 ssl_rsa_kek_source_y[0x10] __attribute__((aligned(4))) = { 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; +static const u8 ssl_rsa_kek_source_y_dev[0x10] __attribute__((aligned(4))) = { + 0xD5, 0xD2, 0xFC, 0x00, 0xFD, 0x49, 0xDD, 0xF8, 0xEE, 0x7B, 0xC4, 0x4B, 0xE1, 0x4C, 0xAA, 0x99}; +static const u8 ssl_client_cert_kek_source[0x10] __attribute__((aligned(4))) = { + 0x64, 0xB8, 0x30, 0xDD, 0x0F, 0x3C, 0xB7, 0xFB, 0x4C, 0x16, 0x01, 0x97, 0xEA, 0x9D, 0x12, 0x10}; +static const u8 ssl_client_cert_key_source[0x10] __attribute__((aligned(4))) = { + 0x4D, 0x92, 0x5A, 0x69, 0x42, 0x23, 0xBB, 0x92, 0x59, 0x16, 0x3E, 0x51, 0x8C, 0x78, 0x14, 0x0F}; static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ diff --git a/source/keys/keys.c b/source/keys/keys.c index 0b325f1..941a801 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -235,6 +235,14 @@ static void _derive_eticket_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *ou se_aes_crypt_block_ecb(ks, DECRYPT, out_rsa_kek, kek_source); } +static void _derive_ssl_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *master_key, const void *kekek_source, const void *kek_source) { + u8 kek_seed[AES_128_KEY_SIZE]; + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + kek_seed[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; + _generate_kek(8, kekek_source, master_key, kek_seed, NULL); + se_aes_crypt_block_ecb(8, DECRYPT, out_rsa_kek, kek_source); +} + static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { _get_device_key(8, keys, keys->temp_key, 0); @@ -244,11 +252,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { _derive_eticket_rsa_kek(keys, 8, keys->eticket_rsa_kek, keys->master_key[0], is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); - - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; - _generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, keys->ssl_rsa_kek, ssl_rsa_kek_source_y); + _derive_ssl_rsa_kek(keys, 8, keys->ssl_rsa_kek, keys->master_key[0], ssl_rsa_kek_source_x, is_dev ? ssl_rsa_kek_source_y_dev : ssl_rsa_kek_source_y); } } @@ -446,6 +450,74 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { return true; } +static bool _read_cal0(void *read_buffer) { + if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, read_buffer)) { + EPRINTF("Unable to read PRODINFO."); + return false; + } + + se_aes_xts_crypt(1, 0, DECRYPT, 0, read_buffer, read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)read_buffer; + if (cal0->magic != MAGIC_CAL0) { + EPRINTF("Invalid CAL0 magic. Check BIS key 0."); + return false; + } + + return true; +} + +static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { + if (!_read_cal0(titlekey_buffer->read_buffer)) { + return false; + } + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; + u32 keypair_generation = 0; + const void *ssl_device_key = NULL; + const void *ssl_iv = NULL; + u32 key_size = 0; + + if (cal0->ext_ssl_key_crc == crc16_calc(cal0->ext_ssl_key_iv, 0x13E)) { + ssl_device_key = cal0->ext_ssl_key; + ssl_iv = cal0->ext_ssl_key_iv; + key_size = 0x120; + + // settings sysmodule manually zeroes this out below cal version 9 + keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; + } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, 0x11E)) { + ssl_device_key = cal0->ssl_key; + ssl_iv = cal0->ssl_key_iv; + key_size = 0x100; + } else { + EPRINTF("Crc16 error reading device key."); + return false; + } + + if (keypair_generation) { + keypair_generation--; + _get_device_key(7, keys, keys->temp_key, keypair_generation); + _derive_ssl_rsa_kek(keys, 7, keys->ssl_rsa_kek_personalized, keys->temp_key, ssl_client_cert_kek_source, ssl_client_cert_key_source); + + memcpy(keys->temp_key, keys->ssl_rsa_kek_personalized, sizeof(keys->temp_key)); + } else { + memcpy(keys->temp_key, keys->ssl_rsa_kek, sizeof(keys->temp_key)); + } + + se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); + se_aes_crypt_ctr(6, &keys->ssl_rsa_key, sizeof(keys->ssl_rsa_key), ssl_device_key, sizeof(keys->ssl_rsa_key), ssl_iv); + + if (key_size == 0x120) { + if (_key_exists(keys->ssl_rsa_key + 0x100)) { + EPRINTF("Invalid SSL key."); + memset(&keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); + return false; + } + } + + return true; +} + static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { if (!_key_exists(keys->eticket_rsa_kek)) { return false; @@ -453,19 +525,11 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, titlekey_buffer->read_buffer)) { - EPRINTF("Unable to read PRODINFO."); + if (!_read_cal0(titlekey_buffer->read_buffer)) { return false; } - se_aes_xts_crypt(1, 0, DECRYPT, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - if (cal0->magic != MAGIC_CAL0) { - EPRINTF("Invalid CAL0 magic. Check BIS key 0."); - return false; - } - u32 keypair_generation = 0; const void *eticket_device_key = NULL; const void *eticket_iv = NULL; @@ -575,6 +639,9 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit if (!res) { EPRINTF("Unable to derive titlekeys."); } + + _derive_personalized_ssl_key(keys, titlekey_buffer); + f_mount(NULL, "bis:", 1); nx_emmc_gpt_free(&gpt); @@ -751,8 +818,10 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(sd_seed, keys->sd_seed); SAVE_KEY_VAR(secure_boot_key, keys->sbk); SAVE_KEY_VAR(ssl_rsa_kek, keys->ssl_rsa_kek); + SAVE_KEY_VAR(ssl_rsa_kek_personalized, keys->ssl_rsa_kek_personalized); SAVE_KEY(ssl_rsa_kek_source_x); SAVE_KEY(ssl_rsa_kek_source_y); + _save_key("ssl_rsa_key", keys->ssl_rsa_key, RSA_2048_KEY_SIZE, text_buffer); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); SAVE_KEY_VAR(tsec_key, keys->tsec_key); diff --git a/source/keys/keys.h b/source/keys/keys.h index 0d65681..c0440d8 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -117,6 +117,8 @@ typedef struct { eticket_rsa_kek[AES_128_KEY_SIZE], eticket_rsa_kek_personalized[AES_128_KEY_SIZE], ssl_rsa_kek[AES_128_KEY_SIZE], + ssl_rsa_kek_personalized[AES_128_KEY_SIZE], + ssl_rsa_key[RSA_2048_KEY_SIZE + 0x20], // keyblob-derived families keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index 59b766e..a1cfaa6 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -112,8 +112,10 @@ typedef struct _nx_emmc_cal0_t u8 crc16_pad16[0x10]; u8 ecc_p33_ticket_cert[0x180]; u8 crc16_pad17[0x10]; - u8 ssl_key[0x110]; - u8 crc16_pad18[0x10]; + u8 ssl_key_iv[0x10]; + u8 ssl_key[0x100]; + u8 crc16_pad18[0xE]; + u16 ssl_key_crc; u32 ssl_cert_size; u8 crc16_pad19[0xC]; u8 ssl_cert[0x800]; @@ -170,8 +172,11 @@ typedef struct _nx_emmc_cal0_t u32 ext_ecc_rsa2048_eticket_key_ver; u8 crc16_pad38[0xA]; u16 ext_ecc_rsa2048_eticket_key_crc; - u8 ext_ssl_key[0x130]; - u8 crc16_pad39[0x10]; + u8 ext_ssl_key_iv[0x10]; + u8 ext_ssl_key[0x120]; + u32 ext_ssl_key_ver; + u8 crc16_pad39[0xA]; + u16 ext_ssl_key_crc; u8 ext_gc_key[0x130]; u8 crc16_pad40[0x10]; From 7a4a99c008cad8140bcaefe83f493afb9b445331 Mon Sep 17 00:00:00 2001 From: dezem Date: Wed, 12 Oct 2022 00:02:39 +0200 Subject: [PATCH 152/166] Add support firmware 15.0.0 --- source/hos/hos.h | 3 ++- source/keys/key_sources.inl | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/hos/hos.h b/source/hos/hos.h index b4111c7..9663d07 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -34,6 +34,7 @@ #define KB_FIRMWARE_VERSION_1210 11 #define KB_FIRMWARE_VERSION_1300 12 #define KB_FIRMWARE_VERSION_1400 13 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1400 //!TODO: Update on mkey changes. +#define KB_FIRMWARE_VERSION_1500 14 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1500 //!TODO: Update on mkey changes. #endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index ef2f044..fe6d577 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -38,6 +38,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0 {0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0 {0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81}, //14.0.0 + {0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67}, //15.0.0 }; //!TODO: Update on mkey changes. @@ -56,6 +57,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */ {0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */ {0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38}, /* Master key 0C encrypted with Master key 0D. */ + {0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7}, /* Master key 0D encrypted with Master key 0E. */ }; //!TODO: Update on mkey changes. @@ -74,6 +76,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr {0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C}, /* Master key 0A encrypted with Master key 0B. */ {0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */ {0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12}, /* Master key 0C encrypted with Master key 0D. */ + {0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D}, /* Master key 0D encrypted with Master key 0E. */ }; static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { @@ -137,6 +140,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0. {0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6}, // 13.0.0. {0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A}, // 14.0.0. + {0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D}, // 15.0.0. }; //!TODO: Update on mkey changes. static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. @@ -148,6 +152,7 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0. {0x4D, 0x5A, 0xB2, 0xC9, 0xE9, 0xE4, 0x4E, 0xA4, 0xD3, 0xBF, 0x94, 0x12, 0x36, 0x30, 0xD0, 0x7F}, // 13.0.0. {0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87}, // 14.0.0. + {0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7}, // 15.0.0. }; //!TODO: Update on mkey changes. static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -162,6 +167,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ {0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D}, /* 14.0.0 Device Master Key Source Source. */ + {0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6}, /* 15.0.0 Device Master Key Source Source. */ }; //!TODO: Update on mkey changes. // from ES @@ -198,6 +204,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ {0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2}, /* 14.0.0 Device Master Kek Source. */ + {0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49}, /* 15.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -212,6 +219,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ {0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA}, /* 14.0.0 Device Master Kek Source. */ + {0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E}, /* 15.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. // from SPL From e8d66f318d94af1ea3fb54cbb4f421d754c3a981 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 29 Oct 2022 15:11:13 -0700 Subject: [PATCH 153/166] keys: Refactor key crypto, fix SSL key dumping --- bdk/sec/se.c | 36 +-- source/keys/key_sources.inl | 23 +- source/keys/keys.c | 489 +++++++++++++++++++++++++----------- source/keys/keys.h | 30 ++- 4 files changed, 398 insertions(+), 180 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 45652dc..02f6f90 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -721,31 +721,31 @@ out:; // _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { - u8 cur_hash[0x20] __attribute__((aligned(4))); - u8 hash_buf[0xe4] __attribute__((aligned(4))); + u8 cur_hash[0x20] __attribute__((aligned(4))); + u8 hash_buf[0xe4] __attribute__((aligned(4))); - u32 hash_buf_size = seed_size + 4; - memcpy(hash_buf, seed, seed_size); - u32 round_num = 0; + u32 hash_buf_size = seed_size + 4; + memcpy(hash_buf, seed, seed_size); + u32 round_num = 0; - u8 *p_out = (u8 *)masked; + u8 *p_out = (u8 *)masked; - while (masked_size) { - u32 cur_size = MIN(masked_size, 0x20); + while (masked_size) { + u32 cur_size = MIN(masked_size, 0x20); - for (u32 i = 0; i < 4; i++) - hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; - round_num++; + for (u32 i = 0; i < 4; i++) + hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; + round_num++; - se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size); + se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size); - for (unsigned int i = 0; i < cur_size; i++) { - *p_out ^= cur_hash[i]; - p_out++; - } + for (unsigned int i = 0; i < cur_size; i++) { + *p_out ^= cur_hash[i]; + p_out++; + } - masked_size -= cur_size; - } + masked_size -= cur_size; + } } u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size) diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index fe6d577..bff4f9b 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -100,12 +100,15 @@ static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { // from Package1 -> Secure_Monitor static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_seal_key_mask_decrypt_device_unique_data[0x10] __attribute__((aligned(4))) = { - 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_seal_key_mask_import_es_device_key[0x10] __attribute__((aligned(4))) = { - 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; -static const u8 aes_seal_key_mask_decrypt_ssl_client_cert_key[0x10] __attribute__((aligned(4))) = { - 0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75}; +static const u8 seal_key_masks[][0x10] __attribute__((aligned(4))) = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // SealKey_LoadAesKey + {0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}, // SealKey_DecryptDeviceUniqueData + {0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C}, // SealKey_ImportLotusKey + {0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}, // SealKey_ImportEsDeviceKey + {0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31}, // SealKey_ReencryptDeviceUniqueData + {0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75}, // SealKey_ImportSslKey + {0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61}, // SealKey_ImportEsClientCertKey +}; static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { @@ -181,12 +184,14 @@ static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; // from SSL -static const u8 ssl_rsa_kek_source_x[0x10] __attribute__((aligned(4))) = { +static const u8 ssl_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; -static const u8 ssl_rsa_kek_source_y[0x10] __attribute__((aligned(4))) = { +static const u8 ssl_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; -static const u8 ssl_rsa_kek_source_y_dev[0x10] __attribute__((aligned(4))) = { +static const u8 ssl_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { 0xD5, 0xD2, 0xFC, 0x00, 0xFD, 0x49, 0xDD, 0xF8, 0xEE, 0x7B, 0xC4, 0x4B, 0xE1, 0x4C, 0xAA, 0x99}; +static const u8 ssl_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { + 0xED, 0x36, 0xB1, 0x32, 0x27, 0x17, 0xD2, 0xB0, 0xBA, 0x1F, 0xC1, 0xBD, 0x4D, 0x38, 0x0F, 0x5E}; static const u8 ssl_client_cert_kek_source[0x10] __attribute__((aligned(4))) = { 0x64, 0xB8, 0x30, 0xDD, 0x0F, 0x3C, 0xB7, 0xFB, 0x4C, 0x16, 0x01, 0x97, 0xEA, 0x9D, 0x12, 0x10}; static const u8 ssl_client_cert_key_source[0x10] __attribute__((aligned(4))) = { diff --git a/source/keys/keys.c b/source/keys/keys.c index 941a801..ceb40f5 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -73,10 +73,14 @@ static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); -static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed); -static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key); -static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation); -static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision); +static void _generate_aes_kek(u32 ks, key_derivation_ctx_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option); +static void _generate_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source); +static void _load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source); +static void _get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source); +static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation, u32 option); +static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation); +static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation); +static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt); // titlekey functions static bool _test_key_pair(const void *E, const void *D, const void *N); @@ -87,8 +91,7 @@ static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) { // Relies on the Mariko KEK being properly set in slot 12 se_aes_crypt_block_ecb(12, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); // mkek = unwrap(mariko_kek, mariko_kek_source) - se_aes_key_set(8, keys->master_kek[i], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) - se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i], master_key_source); + _load_aes_key(8, keys->master_key[i], keys->master_kek[i], master_key_source); } } @@ -116,18 +119,15 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool // Derive all master keys based on current root key for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks) - se_aes_key_set(8, keys->master_kek[i + KB_FIRMWARE_VERSION_620], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) - se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source); + _load_aes_key(8, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); } } // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { - se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); + _load_aes_key(8, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); } - se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, DECRYPT, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); + _load_aes_key(8, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); if (_key_exists(keys->temp_key)) { EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); @@ -166,8 +166,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { minerva_periodic_training(); se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(14, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) - se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); - se_aes_crypt_block_ecb(7, DECRYPT, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) + _load_aes_key(7, keys->keyblob_mac_key[i], keys->keyblob_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) if (i == 0) { se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); @@ -191,82 +190,84 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { memcpy(keys->package1_key[i], keys->keyblob[i].package1_key, sizeof(keys->package1_key[i])); memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); - se_aes_key_set(7, keys->master_kek[i], sizeof(keys->master_kek[i])); if (!_key_exists(keys->master_key[i])) { - se_aes_crypt_block_ecb(7, DECRYPT, keys->master_key[i], master_key_source); + _load_aes_key(7, keys->master_key[i], keys->master_kek[i], master_key_source); } } free(keyblob_block); } static void _derive_bis_keys(key_derivation_ctx_t *keys) { - /* key = unwrap(source, wrapped_key): - key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key - */ minerva_periodic_training(); - u32 key_generation = fuse_read_odm_keygen_rev(); - if (key_generation) - key_generation--; + u32 generation = fuse_read_odm_keygen_rev(); - if (!(_key_exists(keys->device_key) || (key_generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { + if (!(_key_exists(keys->device_key) || (generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { return; } - _generate_specific_aes_key(8, keys, &keys->bis_key[0], &bis_key_sources[0], key_generation); - // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _get_device_key(8, keys, keys->temp_key, key_generation); - _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) - se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2); - memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); + _generate_specific_aes_key(8, keys, &keys->bis_key[0], bis_key_sources[0], generation); + u32 access_key[AES_128_KEY_SIZE / 4] = {0}; + const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); + _generate_aes_kek(8, keys, access_key, bis_kek_source, generation, option); + _generate_aes_key(8, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); + _generate_aes_key(8, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); + memcpy(keys->bis_key[3], keys->bis_key[2], sizeof(keys->bis_key[3])); } static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { - _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_ecb(8, DECRYPT, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2); + const u32 generation = 0; + const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); + _generate_aes_kek(8, keys, keys->temp_key, header_kek_source, generation, option); + _generate_aes_key(8, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); } } -static void _derive_eticket_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *master_key, const void *kek_source) { - u8 kek_seed[AES_128_KEY_SIZE]; - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - kek_seed[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; - _generate_kek(ks, eticket_rsa_kekek_source, master_key, kek_seed, NULL); - se_aes_crypt_block_ecb(ks, DECRYPT, out_rsa_kek, kek_source); +static void _derive_eticket_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *kek_source, u32 generation, u32 option) { + void *access_key = keys->temp_key; + _generate_aes_kek(ks, keys, access_key, eticket_rsa_kekek_source, generation, option); + _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); + } -static void _derive_ssl_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *master_key, const void *kekek_source, const void *kek_source) { - u8 kek_seed[AES_128_KEY_SIZE]; - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - kek_seed[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; - _generate_kek(8, kekek_source, master_key, kek_seed, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, out_rsa_kek, kek_source); +static void _derive_ssl_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { + void *access_key = keys->temp_key; + _generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); + _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); } static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { - _get_device_key(8, keys, keys->temp_key, 0); - _generate_kek(8, save_mac_kek_source, keys->temp_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, keys->save_mac_key, save_mac_key_source); + void *access_key = keys->temp_key; + const u32 generation = 0; + const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); + _generate_aes_kek(8, keys, access_key, save_mac_kek_source, generation, option); + _load_aes_key(8, keys->save_mac_key, access_key, save_mac_key_source); } if (_key_exists(keys->master_key[0])) { - _derive_eticket_rsa_kek(keys, 8, keys->eticket_rsa_kek, keys->master_key[0], is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); - _derive_ssl_rsa_kek(keys, 8, keys->ssl_rsa_kek, keys->master_key[0], ssl_rsa_kek_source_x, is_dev ? ssl_rsa_kek_source_y_dev : ssl_rsa_kek_source_y); + const void *eticket_kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; + const u32 generation = 0; + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); + _derive_eticket_rsa_kek(keys, 8, keys->eticket_rsa_kek, eticket_kek_source, generation, option); + + const void *ssl_kek_source = is_dev ? ssl_rsa_kek_source_dev : ssl_rsa_kek_source; + option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); + _derive_ssl_rsa_kek(keys, 8, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); } } static void _derive_per_generation_keys(key_derivation_ctx_t *keys) { - for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) { - if (!_key_exists(keys->master_key[i])) + for (u32 generation = 0; generation < ARRAY_SIZE(keys->master_key); generation++) { + if (!_key_exists(keys->master_key[generation])) continue; - for (u32 j = 0; j < 3; j++) { - _generate_kek(8, key_area_key_sources[j], keys->master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, DECRYPT, keys->key_area_key[j][i], aes_key_generation_source); + for (u32 source_type = 0; source_type < ARRAY_SIZE(key_area_key_sources); source_type++) { + void *access_key = keys->temp_key; + const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); + _generate_aes_kek(8, keys, access_key, key_area_key_sources[source_type], generation + 1, option); + _load_aes_key(8, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); } - se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, DECRYPT, keys->package2_key[i], package2_key_source); - se_aes_crypt_block_ecb(8, DECRYPT, keys->titlekek[i], titlekek_source); + _load_aes_key(8, keys->package2_key[generation], keys->master_key[generation], package2_key_source); + _load_aes_key(8, keys->titlekek[generation], keys->master_key[generation], titlekek_source); } } @@ -343,6 +344,10 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } + if (is_personalized) { + se_rsa_key_set(0, rsa_keypair->modulus, sizeof(rsa_keypair->modulus), rsa_keypair->private_exponent, sizeof(rsa_keypair->private_exponent)); + } + const u32 ticket_sig_type_rsa2048_sha256 = 0x10004; offset = 0; @@ -467,6 +472,29 @@ static bool _read_cal0(void *read_buffer) { return true; } +static bool _get_rsa_ssl_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { + const u32 ext_key_size = sizeof(cal0->ext_ssl_key_iv) + sizeof(cal0->ext_ssl_key); + const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ssl_key_ver) + sizeof(cal0->crc16_pad39); + const u32 key_size = sizeof(cal0->ssl_key_iv) + sizeof(cal0->ssl_key); + const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad18); + + if (cal0->ext_ssl_key_crc == crc16_calc(cal0->ext_ssl_key_iv, ext_key_crc_size)) { + *out_key = cal0->ext_ssl_key; + *out_key_size = ext_key_size; + *out_iv = cal0->ext_ssl_key_iv; + // settings sysmodule manually zeroes this out below cal version 9 + *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; + } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, key_crc_size)) { + *out_key = cal0->ssl_key; + *out_key_size = key_size; + *out_iv = cal0->ssl_key_iv; + *out_generation = 0; + } else { + return false; + } + return true; +} + static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { if (!_read_cal0(titlekey_buffer->read_buffer)) { return false; @@ -477,40 +505,59 @@ static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_bu const void *ssl_device_key = NULL; const void *ssl_iv = NULL; u32 key_size = 0; + void *keypair_ctr_key = NULL; + bool enforce_unique = true; - if (cal0->ext_ssl_key_crc == crc16_calc(cal0->ext_ssl_key_iv, 0x13E)) { - ssl_device_key = cal0->ext_ssl_key; - ssl_iv = cal0->ext_ssl_key_iv; - key_size = 0x120; - - // settings sysmodule manually zeroes this out below cal version 9 - keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; - } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, 0x11E)) { - ssl_device_key = cal0->ssl_key; - ssl_iv = cal0->ssl_key_iv; - key_size = 0x100; - } else { + if (!_get_rsa_ssl_key(cal0, &ssl_device_key, &key_size, &ssl_iv, &keypair_generation)) { EPRINTF("Crc16 error reading device key."); return false; } - if (keypair_generation) { - keypair_generation--; - _get_device_key(7, keys, keys->temp_key, keypair_generation); - _derive_ssl_rsa_kek(keys, 7, keys->ssl_rsa_kek_personalized, keys->temp_key, ssl_client_cert_kek_source, ssl_client_cert_key_source); + if (key_size == SSL_RSA_KEYPAIR_SIZE) { + bool all_zero = true; + const u8 *key8 = (const u8 *)ssl_device_key; + for (u32 i = RSA_2048_KEY_SIZE; i < SSL_RSA_KEYPAIR_SIZE; i++) { + if (key8[i] != 0) { + all_zero = false; + break; + } + } + if (all_zero) { + // keypairs of this form are not encrypted + memcpy(keys->ssl_rsa_keypair, ssl_device_key, RSA_2048_KEY_SIZE); + return true; + } - memcpy(keys->temp_key, keys->ssl_rsa_kek_personalized, sizeof(keys->temp_key)); - } else { - memcpy(keys->temp_key, keys->ssl_rsa_kek, sizeof(keys->temp_key)); + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); + keypair_ctr_key = keys->ssl_rsa_kek_legacy; + _derive_ssl_rsa_kek(keys, 7, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, keypair_generation, option); + enforce_unique = false; } - se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &keys->ssl_rsa_key, sizeof(keys->ssl_rsa_key), ssl_device_key, sizeof(keys->ssl_rsa_key), ssl_iv); + if (keypair_generation) { + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; + keypair_ctr_key = keys->ssl_rsa_kek_personalized; + _derive_ssl_rsa_kek(keys, 7, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, keypair_generation, option); + } else { + keypair_ctr_key = keys->ssl_rsa_kek; + } - if (key_size == 0x120) { - if (_key_exists(keys->ssl_rsa_key + 0x100)) { - EPRINTF("Invalid SSL key."); - memset(&keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); + u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; + se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(6, keys->ssl_rsa_keypair, ctr_size, ssl_device_key, ctr_size, ssl_iv); + + if (enforce_unique) { + u32 j_block[AES_128_KEY_SIZE / 4] = {0}; + se_aes_key_set(7, keypair_ctr_key, AES_128_KEY_SIZE); + _ghash(7, j_block, ssl_iv, 0x10, NULL, false); + + u32 calc_mac[AES_128_KEY_SIZE / 4] = {0}; + _ghash(7, calc_mac, keys->ssl_rsa_keypair, ctr_size, j_block, true); + + const u8 *key8 = (const u8 *)ssl_device_key; + if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { + EPRINTF("SSL keypair has invalid GMac."); + memset(keys->ssl_rsa_keypair, 0, sizeof(keys->ssl_rsa_keypair)); return false; } } @@ -518,6 +565,27 @@ static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_bu return true; } +static bool _get_rsa_eticket_key(const nx_emmc_cal0_t *cal0, const void **out_key, const void **out_iv, u32 *out_generation) { + const u32 ext_key_size = sizeof(cal0->ext_ecc_rsa2048_eticket_key_iv) + sizeof(cal0->ext_ecc_rsa2048_eticket_key); + const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ecc_rsa2048_eticket_key_ver) + sizeof(cal0->crc16_pad38); + const u32 key_size = sizeof(cal0->rsa2048_eticket_key_iv) + sizeof(cal0->rsa2048_eticket_key); + const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad21); + + if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, ext_key_crc_size)) { + *out_key = cal0->ext_ecc_rsa2048_eticket_key; + *out_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; + // settings sysmodule manually zeroes this out below cal version 9 + *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; + } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, key_crc_size)) { + *out_key = cal0->rsa2048_eticket_key; + *out_iv = cal0->rsa2048_eticket_key_iv; + *out_generation = 0; + } else { + return false; + } + return true; +} + static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { if (!_key_exists(keys->eticket_rsa_kek)) { return false; @@ -533,61 +601,51 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit u32 keypair_generation = 0; const void *eticket_device_key = NULL; const void *eticket_iv = NULL; + void *keypair_ctr_key = NULL; - if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, 0x24E)) { - eticket_device_key = cal0->ext_ecc_rsa2048_eticket_key; - eticket_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; - - // settings sysmodule manually zeroes this out below cal version 9 - keypair_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; - } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, 0x22E)) { - eticket_device_key = cal0->rsa2048_eticket_key; - eticket_iv = cal0->rsa2048_eticket_key_iv; - } else { + if (!_get_rsa_eticket_key(cal0, &eticket_device_key, &eticket_iv, &keypair_generation)) { EPRINTF("Crc16 error reading device key."); return false; } if (keypair_generation) { - keypair_generation--; - _get_device_key(7, keys, keys->temp_key, keypair_generation); - _derive_eticket_rsa_kek(keys, 7, keys->eticket_rsa_kek_personalized, keys->temp_key, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source); - memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key)); + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; + _derive_eticket_rsa_kek(keys, 7, keys->eticket_rsa_kek_personalized, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source, keypair_generation, option); + keypair_ctr_key = keys->eticket_rsa_kek_personalized; } else { - memcpy(keys->temp_key, keys->eticket_rsa_kek, sizeof(keys->temp_key)); + keypair_ctr_key = keys->eticket_rsa_kek; } - se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &keys->rsa_keypair, sizeof(keys->rsa_keypair), eticket_device_key, sizeof(keys->rsa_keypair), eticket_iv); + se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(6, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); - // Check public exponent is 65537 big endian - if (_read_be_u32(keys->rsa_keypair.public_exponent, 0) != 65537) { + if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { // try legacy kek source - _derive_eticket_rsa_kek(keys, 7, keys->temp_key, keys->master_key[0], eticket_rsa_kek_source_legacy); + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); + keypair_ctr_key = keys->temp_key; + _derive_eticket_rsa_kek(keys, 7, keypair_ctr_key, eticket_rsa_kek_source_legacy, 0, option); - se_aes_key_set(6, keys->temp_key, sizeof(keys->temp_key)); - se_aes_crypt_ctr(6, &keys->rsa_keypair, sizeof(keys->rsa_keypair), eticket_device_key, sizeof(keys->rsa_keypair), eticket_iv); + se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(6, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); - if (_read_be_u32(keys->rsa_keypair.public_exponent, 0) != 65537) { + if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { EPRINTF("Invalid public exponent."); - memset(&keys->rsa_keypair, 0, sizeof(keys->rsa_keypair)); + memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); return false; } else { memcpy(keys->eticket_rsa_kek, keys->temp_key, sizeof(keys->eticket_rsa_kek)); } } - if (!_test_key_pair(keys->rsa_keypair.public_exponent, keys->rsa_keypair.private_exponent, keys->rsa_keypair.modulus)) { + if (!_test_key_pair(keys->eticket_rsa_keypair.public_exponent, keys->eticket_rsa_keypair.private_exponent, keys->eticket_rsa_keypair.modulus)) { EPRINTF("Invalid keypair. Check eticket_rsa_kek."); - memset(&keys->rsa_keypair, 0, sizeof(keys->rsa_keypair)); + memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); return false; } - se_rsa_key_set(0, keys->rsa_keypair.modulus, sizeof(keys->rsa_keypair.modulus), keys->rsa_keypair.private_exponent, sizeof(keys->rsa_keypair.private_exponent)); - const u32 buf_size = SZ_16K; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); - _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &keys->rsa_keypair); + _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &keys->eticket_rsa_keypair); gfx_printf("\n%k Found %d titlekeys.\n\n", colors[(color_idx++) % 6], _titlekey_count); @@ -771,7 +829,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(eticket_rsa_kek_source); } SAVE_KEY(eticket_rsa_kekek_source); - _save_key("eticket_rsa_keypair", &keys->rsa_keypair, sizeof(keys->rsa_keypair), text_buffer); + _save_key("eticket_rsa_keypair", &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), text_buffer); SAVE_KEY(header_kek_source); SAVE_KEY_VAR(header_key, keys->header_key); SAVE_KEY(header_key_source); @@ -800,12 +858,6 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(package2_key_source); SAVE_KEY(per_console_key_source); SAVE_KEY(retail_specific_aes_key_source); - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_import_es_device_key[i]; - SAVE_KEY_VAR(rsa_oaep_kek_generation_source, keys->temp_key); - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_seal_key_mask_decrypt_device_unique_data[i]; - SAVE_KEY_VAR(rsa_private_kek_generation_source, keys->temp_key); SAVE_KEY(save_mac_kek_source); SAVE_KEY_VAR(save_mac_key, keys->save_mac_key); SAVE_KEY(save_mac_key_source); @@ -819,9 +871,13 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(secure_boot_key, keys->sbk); SAVE_KEY_VAR(ssl_rsa_kek, keys->ssl_rsa_kek); SAVE_KEY_VAR(ssl_rsa_kek_personalized, keys->ssl_rsa_kek_personalized); - SAVE_KEY(ssl_rsa_kek_source_x); - SAVE_KEY(ssl_rsa_kek_source_y); - _save_key("ssl_rsa_key", keys->ssl_rsa_key, RSA_2048_KEY_SIZE, text_buffer); + if (is_dev) { + SAVE_KEY_VAR(ssl_rsa_kek_source, ssl_rsa_kek_source_dev); + } else { + SAVE_KEY(ssl_rsa_kek_source); + } + SAVE_KEY(ssl_rsa_kekek_source); + _save_key("ssl_rsa_keypair", keys->ssl_rsa_keypair, RSA_2048_KEY_SIZE, text_buffer); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); SAVE_KEY_VAR(tsec_key, keys->tsec_key); @@ -1013,7 +1069,7 @@ void derive_amiibo_keys() { return; } - _decrypt_aes_key(8, keys->temp_key, nfc_key_source, keys->master_key[0]); + _decrypt_aes_key(8, keys, keys->temp_key, nfc_key_source, 0, 0); nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; static const u8 nfc_iv[AES_128_KEY_SIZE] = { @@ -1130,30 +1186,60 @@ static void _save_key_family(const char *name, const void *data, u32 start_key, free(temp_name); } -// Equivalent to spl::GenerateAesKek. When key_seed is set, the result is as if spl::GenerateAesKey was called immediately after. -// The generation and option args are dictated by master_key and kek_seed. -static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed) { - if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) - return; +// Equivalent to spl::GenerateAesKek +static void _generate_aes_kek(u32 ks, key_derivation_ctx_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option) { + bool device_unique = GET_IS_DEVICE_UNIQUE(option); + u32 seal_key_index = GET_SEAL_KEY_INDEX(option); - se_aes_key_set(ks, master_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, kek_seed); - se_aes_unwrap_key(ks, ks, key_source); - if (key_seed && _key_exists(key_seed)) - se_aes_unwrap_key(ks, ks, key_seed); + if (generation) + generation--; + + u8 static_source[AES_128_KEY_SIZE]; + for (u32 i = 0; i < AES_128_KEY_SIZE; i++) + static_source[i] = aes_kek_generation_source[i] ^ seal_key_masks[seal_key_index][i]; + + if (device_unique) { + _get_device_key(ks, keys, keys->temp_key, generation); + } else { + memcpy(keys->temp_key, keys->master_key[generation], sizeof(keys->temp_key)); + } + se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); + se_aes_unwrap_key(ks, ks, static_source); + se_aes_crypt_block_ecb(ks, DECRYPT, out_kek, kek_source); +} + +// Based on spl::LoadAesKey but instead of prepping keyslot, returns calculated key +static void _load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { + se_aes_key_set(ks, access_key, AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(ks, DECRYPT, out_key, key_source); +} + +// Equivalent to spl::GenerateAesKey +static void _generate_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source) { + void *aes_key = keys->temp_key; + _load_aes_key(ks, aes_key, access_key, aes_key_generation_source); + se_aes_key_set(ks, aes_key, AES_128_KEY_SIZE); + se_aes_crypt_ecb(ks, DECRYPT, out_key, key_size, key_source, key_size); +} + +// Equivalent to smc::PrepareDeviceUniqueDataKey but with no sealing +static void _get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { + _load_aes_key(ks, out_key, access_key, key_source); } // Equivalent to spl::DecryptAesKey. -static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key) { - _generate_kek(ks, aes_key_decryption_source, master_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(ks, 0, dst, key_source); +static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation, u32 option) { + void *access_key = keys->temp_key; + _generate_aes_kek(ks, keys, access_key, aes_key_decryption_source, generation, option); + _generate_aes_key(ks, keys, out_key, AES_128_KEY_SIZE, access_key, key_source); } -static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) { +// Equivalent to smc::GetSecureData +static void _get_secure_data(key_derivation_ctx_t *keys, void *out_data) { se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE); - u8 *d = (u8 *)dst; - se_aes_crypt_ctr(6, d + 0x00, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); - se_aes_crypt_ctr(6, d + 0x10, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + u8 *d = (u8 *)out_data; + se_aes_crypt_ctr(6, d + AES_128_KEY_SIZE * 0, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + se_aes_crypt_ctr(6, d + AES_128_KEY_SIZE * 1, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); // Apply tweak for (u32 i = 0; i < AES_128_KEY_SIZE; i++) { @@ -1161,9 +1247,10 @@ static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) { } } -static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 key_generation) { +// Equivalent to spl::GenerateSpecificAesKey +static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation) { if (fuse_read_bootrom_rev() >= 0x7F) { - _get_device_key(ks, keys, keys->temp_key, key_generation); + _get_device_key(ks, keys, keys->temp_key, generation - 1); se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) @@ -1172,24 +1259,124 @@ static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void } } -static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision) { - if (revision == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) { +static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation) { + if (generation == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) { memcpy(out_device_key, keys->device_key, AES_128_KEY_SIZE); return; } - if (revision >= KB_FIRMWARE_VERSION_400) { - revision -= KB_FIRMWARE_VERSION_400; + if (generation >= KB_FIRMWARE_VERSION_400) { + generation -= KB_FIRMWARE_VERSION_400; } else { - revision = 0; + generation = 0; } - u32 temp_key[AES_128_KEY_SIZE / 4] = {0}; - se_aes_key_set(ks, keys->device_key_4x, AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(ks, DECRYPT, temp_key, device_master_key_source_sources[revision]); + u32 temp_key_source[AES_128_KEY_SIZE / 4] = {0}; + _load_aes_key(ks, temp_key_source, keys->device_key_4x, device_master_key_source_sources[generation]); + const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[generation] : device_master_kek_sources_dev[generation]; se_aes_key_set(ks, keys->master_key[0], AES_128_KEY_SIZE); - const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[revision] : device_master_kek_sources_dev[revision]; se_aes_unwrap_key(ks, ks, kek_source); - se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key); + se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key_source); +} + +// The following ghash implementation is from Atmosphère's original exosphere implementation + +/* Shifts right a little endian 128-bit value. */ +static void _shr_128(uint64_t *val) { + val[0] >>= 1; + val[0] |= (val[1] & 1) << 63; + val[1] >>= 1; +} + +/* Shifts left a little endian 128-bit value. */ +static void _shl_128(uint64_t *val) { + val[1] <<= 1; + val[1] |= (val[0] & (1ull << 63)) >> 63; + val[0] <<= 1; +} + +/* Multiplies two 128-bit numbers X,Y in the GF(128) Galois Field. */ +static void _gf128_mul(uint8_t *dst, const uint8_t *x, const uint8_t *y) { + uint8_t x_work[0x10]; + uint8_t y_work[0x10]; + uint8_t dst_work[0x10]; + + uint64_t *p_x = (uint64_t *)(&x_work[0]); + uint64_t *p_y = (uint64_t *)(&y_work[0]); + uint64_t *p_dst = (uint64_t *)(&dst_work[0]); + + /* Initialize buffers. */ + for (unsigned int i = 0; i < 0x10; i++) { + x_work[i] = x[0xF-i]; + y_work[i] = y[0xF-i]; + dst_work[i] = 0; + } + + /* Perform operation for each bit in y. */ + for (unsigned int round = 0; round < 0x80; round++) { + p_dst[0] ^= p_x[0] * ((y_work[0xF] & 0x80) >> 7); + p_dst[1] ^= p_x[1] * ((y_work[0xF] & 0x80) >> 7); + _shl_128(p_y); + uint8_t xval = 0xE1 * (x_work[0] & 1); + _shr_128(p_x); + x_work[0xF] ^= xval; + } + + for (unsigned int i = 0; i < 0x10; i++) { + dst[i] = dst_work[0xF-i]; + } +} + +static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt) { + uint8_t x[0x10] = {0}; + uint8_t h[0x10]; + + uint64_t *p_x = (uint64_t *)(&x[0]); + uint64_t *p_data = (uint64_t *)src; + + /* H = aes_ecb_encrypt(zeroes) */ + se_aes_crypt_block_ecb(ks, ENCRYPT, h, x); + + u64 total_size = src_size; + + while (src_size >= 0x10) { + /* X = (X ^ current_block) * H */ + p_x[0] ^= p_data[0]; + p_x[1] ^= p_data[1]; + _gf128_mul(x, x, h); + + /* Increment p_data by 0x10 bytes. */ + p_data += 2; + src_size -= 0x10; + } + + /* Nintendo's code *discards all data in the last block* if unaligned. */ + /* And treats that block as though it were all-zero. */ + /* This is a bug, they just forget to XOR with the copy of the last block they save. */ + if (src_size & 0xF) { + _gf128_mul(x, x, h); + } + + uint64_t xor_size = total_size << 3; + xor_size = __builtin_bswap64(xor_size); + + /* Due to a Nintendo bug, the wrong QWORD gets XOR'd in the "final output block" case. */ + if (encrypt) { + p_x[0] ^= xor_size; + } else { + p_x[1] ^= xor_size; + } + + _gf128_mul(x, x, h); + + /* If final output block, XOR with encrypted J block. */ + if (encrypt) { + se_aes_crypt_block_ecb(ks, ENCRYPT, h, j_block); + for (unsigned int i = 0; i < 0x10; i++) { + x[i] ^= h[i]; + } + } + /* Copy output. */ + memcpy(dst, x, 0x10); } static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { diff --git a/source/keys/keys.h b/source/keys/keys.h index c0440d8..cc67c4a 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -24,6 +24,8 @@ #define AES_128_KEY_SIZE 16 #define RSA_2048_KEY_SIZE 256 +#define RSA_PUBLIC_EXPONENT 65537 + // only tickets of type Rsa2048Sha256 are expected typedef struct { u32 signature_type; // always 0x10004 @@ -104,6 +106,29 @@ typedef struct { u8 xor_pad[0x20]; } nfc_save_key_t; +typedef enum { + SEAL_KEY_LOAD_AES_KEY = 0, + SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA = 1, + SEAL_KEY_IMPORT_LOTUS_KEY = 2, + SEAL_KEY_IMPORT_ES_DEVICE_KEY = 3, + SEAL_KEY_REENCRYPT_DEVICE_UNIQUE_DATA = 4, + SEAL_KEY_IMPORT_SSL_KEY = 5, + SEAL_KEY_IMPORT_ES_CLIENT_CERT_KEY = 6, +} seal_key_t; + +typedef enum { + NOT_DEVICE_UNIQUE = 0, + IS_DEVICE_UNIQUE = 1, +} device_unique_t; + +#define SET_SEAL_KEY_INDEX(x) (((x) & 7) << 5) +#define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) +#define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) + +#define WRAPPED_RSA_EXT_DATA_SIZE 0x20 +#define SSL_RSA_KEYPAIR_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) +#define SSL_RSA_EXT_KEYPAIR_SIZE (SSL_RSA_KEYPAIR_SIZE + WRAPPED_RSA_EXT_DATA_SIZE) + typedef struct { u8 temp_key[AES_128_KEY_SIZE], bis_key[4][AES_128_KEY_SIZE * 2], @@ -117,8 +142,9 @@ typedef struct { eticket_rsa_kek[AES_128_KEY_SIZE], eticket_rsa_kek_personalized[AES_128_KEY_SIZE], ssl_rsa_kek[AES_128_KEY_SIZE], + ssl_rsa_kek_legacy[AES_128_KEY_SIZE], ssl_rsa_kek_personalized[AES_128_KEY_SIZE], - ssl_rsa_key[RSA_2048_KEY_SIZE + 0x20], + ssl_rsa_keypair[RSA_2048_KEY_SIZE + 0x20], // keyblob-derived families keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], @@ -133,7 +159,7 @@ typedef struct { tsec_root_key[AES_128_KEY_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; - rsa_keypair_t rsa_keypair; + rsa_keypair_t eticket_rsa_keypair; } key_derivation_ctx_t; typedef struct { From 8207aaa66e2414b3307c2970e2270a16875e5431 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 29 Oct 2022 15:43:17 -0700 Subject: [PATCH 154/166] keys: Name keyslots, use more apt SSL key name --- source/keys/keys.c | 180 ++++++++++++++++++++++----------------------- source/keys/keys.h | 29 +++++++- 2 files changed, 115 insertions(+), 94 deletions(-) diff --git a/source/keys/keys.c b/source/keys/keys.c index ceb40f5..5604180 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -82,16 +82,16 @@ static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation); static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt); // titlekey functions -static bool _test_key_pair(const void *E, const void *D, const void *N); +static bool _test_rsa_keypair(const void *E, const void *D, const void *N); static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 - se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); + se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); // Derive all master keys based on Mariko KEK for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) { // Relies on the Mariko KEK being properly set in slot 12 - se_aes_crypt_block_ecb(12, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); // mkek = unwrap(mariko_kek, mariko_kek_source) - _load_aes_key(8, keys->master_key[i], keys->master_kek[i], master_key_source); + se_aes_crypt_block_ecb(KS_MARIKO_KEK, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); + _load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } @@ -118,16 +118,16 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool u32 tsec_root_key_slot = is_dev ? 11 : 13; // Derive all master keys based on current root key for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { - se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks) - _load_aes_key(8, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); + se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); + _load_aes_key(KS_AES_ECB, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); } } // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { - _load_aes_key(8, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); + _load_aes_key(KS_AES_ECB, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); } - _load_aes_key(8, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); + _load_aes_key(KS_AES_ECB, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); if (_key_exists(keys->temp_key)) { EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); @@ -164,34 +164,34 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); - se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) - se_aes_crypt_block_ecb(14, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) - _load_aes_key(7, keys->keyblob_mac_key[i], keys->keyblob_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) + se_aes_crypt_block_ecb(KS_TSEC, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); + se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); + _load_aes_key(KS_AES_ECB, keys->keyblob_mac_key[i], keys->keyblob_key[i], keyblob_mac_key_source); if (i == 0) { - se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); + se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, keys->device_key, per_console_key_source); + se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); } if (!have_keyblobs) { continue; } - // verify keyblob is not corrupt - se_aes_key_set(10, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i])); - se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); + // Verify keyblob is not corrupt + se_aes_key_set(KS_AES_CMAC, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i])); + se_aes_cmac(KS_AES_CMAC, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t)); if (memcmp(current_keyblob->cmac, keyblob_mac, sizeof(keyblob_mac)) != 0) { EPRINTFARGS("Keyblob %x corrupt.", i); continue; } - // decrypt keyblobs - se_aes_key_set(6, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); - se_aes_crypt_ctr(6, &keys->keyblob[i], sizeof(keyblob_t), ¤t_keyblob->key_data, sizeof(keyblob_t), current_keyblob->iv); + // Decrypt keyblobs + se_aes_key_set(KS_AES_CTR, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); + se_aes_crypt_ctr(KS_AES_CTR, &keys->keyblob[i], sizeof(keyblob_t), ¤t_keyblob->key_data, sizeof(keyblob_t), current_keyblob->iv); memcpy(keys->package1_key[i], keys->keyblob[i].package1_key, sizeof(keys->package1_key[i])); memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); if (!_key_exists(keys->master_key[i])) { - _load_aes_key(7, keys->master_key[i], keys->master_kek[i], master_key_source); + _load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } free(keyblob_block); @@ -204,12 +204,12 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { if (!(_key_exists(keys->device_key) || (generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { return; } - _generate_specific_aes_key(8, keys, &keys->bis_key[0], bis_key_sources[0], generation); + _generate_specific_aes_key(KS_AES_ECB, keys, &keys->bis_key[0], bis_key_sources[0], generation); u32 access_key[AES_128_KEY_SIZE / 4] = {0}; const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); - _generate_aes_kek(8, keys, access_key, bis_kek_source, generation, option); - _generate_aes_key(8, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); - _generate_aes_key(8, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); + _generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); + _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); + _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); memcpy(keys->bis_key[3], keys->bis_key[2], sizeof(keys->bis_key[3])); } @@ -217,19 +217,19 @@ static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { const u32 generation = 0; const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - _generate_aes_kek(8, keys, keys->temp_key, header_kek_source, generation, option); - _generate_aes_key(8, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); + _generate_aes_kek(KS_AES_ECB, keys, keys->temp_key, header_kek_source, generation, option); + _generate_aes_key(KS_AES_ECB, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); } } -static void _derive_eticket_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *kek_source, u32 generation, u32 option) { +static void _derive_eticket_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kek_source, u32 generation, u32 option) { void *access_key = keys->temp_key; _generate_aes_kek(ks, keys, access_key, eticket_rsa_kekek_source, generation, option); _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); } -static void _derive_ssl_rsa_kek(key_derivation_ctx_t *keys, u32 ks, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { +static void _derive_ssl_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { void *access_key = keys->temp_key; _generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); @@ -240,19 +240,19 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { void *access_key = keys->temp_key; const u32 generation = 0; const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); - _generate_aes_kek(8, keys, access_key, save_mac_kek_source, generation, option); - _load_aes_key(8, keys->save_mac_key, access_key, save_mac_key_source); + _generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); + _load_aes_key(KS_AES_ECB, keys->save_mac_key, access_key, save_mac_key_source); } if (_key_exists(keys->master_key[0])) { const void *eticket_kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; const u32 generation = 0; u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); - _derive_eticket_rsa_kek(keys, 8, keys->eticket_rsa_kek, eticket_kek_source, generation, option); + _derive_eticket_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek, eticket_kek_source, generation, option); const void *ssl_kek_source = is_dev ? ssl_rsa_kek_source_dev : ssl_rsa_kek_source; option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); - _derive_ssl_rsa_kek(keys, 8, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); + _derive_ssl_rsa_kek(KS_AES_ECB, keys, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); } } @@ -263,11 +263,11 @@ static void _derive_per_generation_keys(key_derivation_ctx_t *keys) { for (u32 source_type = 0; source_type < ARRAY_SIZE(key_area_key_sources); source_type++) { void *access_key = keys->temp_key; const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - _generate_aes_kek(8, keys, access_key, key_area_key_sources[source_type], generation + 1, option); - _load_aes_key(8, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); + _generate_aes_kek(KS_AES_ECB, keys, access_key, key_area_key_sources[source_type], generation + 1, option); + _load_aes_key(KS_AES_ECB, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); } - _load_aes_key(8, keys->package2_key[generation], keys->master_key[generation], package2_key_source); - _load_aes_key(8, keys->titlekek[generation], keys->master_key[generation], titlekek_source); + _load_aes_key(KS_AES_ECB, keys->package2_key[generation], keys->master_key[generation], package2_key_source); + _load_aes_key(KS_AES_ECB, keys->titlekek[generation], keys->master_key[generation], titlekek_source); } } @@ -425,7 +425,7 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { EPRINTF("Unable to open SD seed vector. Skipping."); return false; } - // get sd seed verification vector + // Get sd seed verification vector if (f_read(&fp, keys->temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); @@ -433,7 +433,7 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { } f_close(&fp); - // this file is small enough that parsing the savedata properly is slower + // This file is small enough that parsing the savedata properly is slower if (f_open(&fp, "bis:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); return false; @@ -482,7 +482,7 @@ static bool _get_rsa_ssl_key(const nx_emmc_cal0_t *cal0, const void **out_key, u *out_key = cal0->ext_ssl_key; *out_key_size = ext_key_size; *out_iv = cal0->ext_ssl_key_iv; - // settings sysmodule manually zeroes this out below cal version 9 + // Settings sysmodule manually zeroes this out below cal version 9 *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, key_crc_size)) { *out_key = cal0->ssl_key; @@ -501,63 +501,63 @@ static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_bu } nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - u32 keypair_generation = 0; + u32 generation = 0; const void *ssl_device_key = NULL; const void *ssl_iv = NULL; u32 key_size = 0; void *keypair_ctr_key = NULL; bool enforce_unique = true; - if (!_get_rsa_ssl_key(cal0, &ssl_device_key, &key_size, &ssl_iv, &keypair_generation)) { + if (!_get_rsa_ssl_key(cal0, &ssl_device_key, &key_size, &ssl_iv, &generation)) { EPRINTF("Crc16 error reading device key."); return false; } - if (key_size == SSL_RSA_KEYPAIR_SIZE) { + if (key_size == SSL_RSA_KEY_SIZE) { bool all_zero = true; const u8 *key8 = (const u8 *)ssl_device_key; - for (u32 i = RSA_2048_KEY_SIZE; i < SSL_RSA_KEYPAIR_SIZE; i++) { + for (u32 i = RSA_2048_KEY_SIZE; i < SSL_RSA_KEY_SIZE; i++) { if (key8[i] != 0) { all_zero = false; break; } } if (all_zero) { - // keypairs of this form are not encrypted - memcpy(keys->ssl_rsa_keypair, ssl_device_key, RSA_2048_KEY_SIZE); + // Keypairs of this form are not encrypted + memcpy(keys->ssl_rsa_key, ssl_device_key, RSA_2048_KEY_SIZE); return true; } u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); keypair_ctr_key = keys->ssl_rsa_kek_legacy; - _derive_ssl_rsa_kek(keys, 7, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, keypair_generation, option); + _derive_ssl_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); enforce_unique = false; } - if (keypair_generation) { + if (generation) { u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; keypair_ctr_key = keys->ssl_rsa_kek_personalized; - _derive_ssl_rsa_kek(keys, 7, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, keypair_generation, option); + _derive_ssl_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); } else { keypair_ctr_key = keys->ssl_rsa_kek; } u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; - se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(6, keys->ssl_rsa_keypair, ctr_size, ssl_device_key, ctr_size, ssl_iv); + se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, ssl_device_key, ctr_size, ssl_iv); if (enforce_unique) { u32 j_block[AES_128_KEY_SIZE / 4] = {0}; - se_aes_key_set(7, keypair_ctr_key, AES_128_KEY_SIZE); - _ghash(7, j_block, ssl_iv, 0x10, NULL, false); + se_aes_key_set(KS_AES_ECB, keypair_ctr_key, AES_128_KEY_SIZE); + _ghash(KS_AES_ECB, j_block, ssl_iv, 0x10, NULL, false); u32 calc_mac[AES_128_KEY_SIZE / 4] = {0}; - _ghash(7, calc_mac, keys->ssl_rsa_keypair, ctr_size, j_block, true); + _ghash(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, j_block, true); const u8 *key8 = (const u8 *)ssl_device_key; if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { EPRINTF("SSL keypair has invalid GMac."); - memset(keys->ssl_rsa_keypair, 0, sizeof(keys->ssl_rsa_keypair)); + memset(keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); return false; } } @@ -574,7 +574,7 @@ static bool _get_rsa_eticket_key(const nx_emmc_cal0_t *cal0, const void **out_ke if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, ext_key_crc_size)) { *out_key = cal0->ext_ecc_rsa2048_eticket_key; *out_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; - // settings sysmodule manually zeroes this out below cal version 9 + // Settings sysmodule manually zeroes this out below cal version 9 *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, key_crc_size)) { *out_key = cal0->rsa2048_eticket_key; @@ -598,35 +598,35 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit } nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - u32 keypair_generation = 0; + u32 generation = 0; const void *eticket_device_key = NULL; const void *eticket_iv = NULL; void *keypair_ctr_key = NULL; - if (!_get_rsa_eticket_key(cal0, &eticket_device_key, &eticket_iv, &keypair_generation)) { + if (!_get_rsa_eticket_key(cal0, &eticket_device_key, &eticket_iv, &generation)) { EPRINTF("Crc16 error reading device key."); return false; } - if (keypair_generation) { + if (generation) { u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; - _derive_eticket_rsa_kek(keys, 7, keys->eticket_rsa_kek_personalized, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source, keypair_generation, option); + _derive_eticket_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek_personalized, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source, generation, option); keypair_ctr_key = keys->eticket_rsa_kek_personalized; } else { keypair_ctr_key = keys->eticket_rsa_kek; } - se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(6, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); + se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { - // try legacy kek source + // Try legacy kek source u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); keypair_ctr_key = keys->temp_key; - _derive_eticket_rsa_kek(keys, 7, keypair_ctr_key, eticket_rsa_kek_source_legacy, 0, option); + _derive_eticket_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kek_source_legacy, 0, option); - se_aes_key_set(6, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(6, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); + se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { EPRINTF("Invalid public exponent."); @@ -637,7 +637,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit } } - if (!_test_key_pair(keys->eticket_rsa_keypair.public_exponent, keys->eticket_rsa_keypair.private_exponent, keys->eticket_rsa_keypair.modulus)) { + if (!_test_rsa_keypair(keys->eticket_rsa_keypair.public_exponent, keys->eticket_rsa_keypair.private_exponent, keys->eticket_rsa_keypair.modulus)) { EPRINTF("Invalid keypair. Check eticket_rsa_kek."); memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); return false; @@ -655,20 +655,20 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { // Set BIS keys. // PRODINFO/PRODINFOF - se_aes_key_set(0, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(1, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_00_0, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_00_1, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); // SAFE - se_aes_key_set(2, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(3, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_01_0, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_01_1, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); // SYSTEM/USER - se_aes_key_set(4, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(5, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_02_0, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_02_1, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); if (!emummc_storage_set_mmc_partition(EMMC_GPP)) { EPRINTF("Unable to set partition."); return false; } - // Parse eMMC GPT. + // Parse eMMC GPT LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &emmc_storage); @@ -877,7 +877,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(ssl_rsa_kek_source); } SAVE_KEY(ssl_rsa_kekek_source); - _save_key("ssl_rsa_keypair", keys->ssl_rsa_keypair, RSA_2048_KEY_SIZE, text_buffer); + _save_key("ssl_rsa_key", keys->ssl_rsa_key, RSA_2048_KEY_SIZE, text_buffer); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); SAVE_KEY_VAR(tsec_key, keys->tsec_key); @@ -931,8 +931,8 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl static bool _check_keyslot_access() { u8 test_data[AES_128_KEY_SIZE] = {0}; const u8 test_ciphertext[AES_128_KEY_SIZE] = {0}; - se_aes_key_set(8, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); - se_aes_crypt_block_ecb(8, DECRYPT, test_data, test_ciphertext); + se_aes_key_set(KS_AES_ECB, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); + se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, test_data, test_ciphertext); return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; } @@ -952,9 +952,9 @@ static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_ u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); - memcpy(&dev_keys->tsec_root_key, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(keys->tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(&prod_keys->tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(keys->tsec_key, aes_keys + KS_TSEC * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * AES_128_KEY_SIZE, AES_128_KEY_SIZE); free(aes_keys); _derive_master_keys_from_latest_key(prod_keys, false); @@ -1069,19 +1069,19 @@ void derive_amiibo_keys() { return; } - _decrypt_aes_key(8, keys, keys->temp_key, nfc_key_source, 0, 0); + _decrypt_aes_key(KS_AES_ECB, keys, keys->temp_key, nfc_key_source, 0, 0); nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; static const u8 nfc_iv[AES_128_KEY_SIZE] = { 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; - se_aes_key_set(6, keys->temp_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(6, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); + se_aes_key_set(KS_AES_CTR, keys->temp_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); minerva_periodic_training(); u8 xor_pad[0x20] __attribute__((aligned(4))) = {0}; - se_aes_key_set(6, nfc_keyblob.ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(6, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); + se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); minerva_periodic_training(); @@ -1236,10 +1236,10 @@ static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, // Equivalent to smc::GetSecureData static void _get_secure_data(key_derivation_ctx_t *keys, void *out_data) { - se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, keys->device_key, AES_128_KEY_SIZE); u8 *d = (u8 *)out_data; - se_aes_crypt_ctr(6, d + AES_128_KEY_SIZE * 0, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); - se_aes_crypt_ctr(6, d + AES_128_KEY_SIZE * 1, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + se_aes_crypt_ctr(KS_AES_CTR, d + AES_128_KEY_SIZE * 0, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); + se_aes_crypt_ctr(KS_AES_CTR, d + AES_128_KEY_SIZE * 1, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); // Apply tweak for (u32 i = 0; i < AES_128_KEY_SIZE; i++) { @@ -1252,8 +1252,8 @@ static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void if (fuse_read_bootrom_rev() >= 0x7F) { _get_device_key(ks, keys, keys->temp_key, generation - 1); se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek) + se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); + se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); } else { _get_secure_data(keys, out_key); } @@ -1379,7 +1379,7 @@ static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void memcpy(dst, x, 0x10); } -static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) { +static bool _test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus) { u8 plaintext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, ciphertext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, work[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}; diff --git a/source/keys/keys.h b/source/keys/keys.h index cc67c4a..3a61684 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -26,6 +26,29 @@ #define RSA_PUBLIC_EXPONENT 65537 +// Lockpick_RCM keyslots +#define KS_BIS_00_0 0 +#define KS_BIS_00_1 1 +#define KS_BIS_01_0 2 +#define KS_BIS_01_1 3 +#define KS_BIS_02_0 4 +#define KS_BIS_02_1 5 +#define KS_AES_CTR 6 +#define KS_AES_ECB 8 +#define KS_AES_CMAC 10 + +// Mariko keyslots +#define KS_MARIKO_KEK 12 +#define KS_MARIKO_BEK 13 + +// Other Switch keyslots +#define KS_TSEC 12 +#define KS_SECURE_BOOT 14 + +// Atmosphere keygen keyslots +#define KS_TSEC_ROOT_DEV 11 +#define KS_TSEC_ROOT 13 + // only tickets of type Rsa2048Sha256 are expected typedef struct { u32 signature_type; // always 0x10004 @@ -125,9 +148,7 @@ typedef enum { #define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) #define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) -#define WRAPPED_RSA_EXT_DATA_SIZE 0x20 -#define SSL_RSA_KEYPAIR_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) -#define SSL_RSA_EXT_KEYPAIR_SIZE (SSL_RSA_KEYPAIR_SIZE + WRAPPED_RSA_EXT_DATA_SIZE) +#define SSL_RSA_KEY_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) typedef struct { u8 temp_key[AES_128_KEY_SIZE], @@ -144,7 +165,7 @@ typedef struct { ssl_rsa_kek[AES_128_KEY_SIZE], ssl_rsa_kek_legacy[AES_128_KEY_SIZE], ssl_rsa_kek_personalized[AES_128_KEY_SIZE], - ssl_rsa_keypair[RSA_2048_KEY_SIZE + 0x20], + ssl_rsa_key[RSA_2048_KEY_SIZE + 0x20], // keyblob-derived families keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], From ab9322af53274392ee35b177af9297d9627408a6 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 29 Oct 2022 15:52:42 -0700 Subject: [PATCH 155/166] Update copyright notice years --- bdk/libs/nx_savedata/header.h | 2 +- bdk/libs/nx_savedata/remap_storage.h | 2 +- bdk/libs/nx_savedata/save_fs_list.h | 2 +- bdk/utils/util.c | 1 + source/keys/key_sources.inl | 2 +- source/keys/keys.c | 2 +- source/keys/keys.h | 2 +- source/storage/nx_emmc_bis.h | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bdk/libs/nx_savedata/header.h b/bdk/libs/nx_savedata/header.h index 4a6e259..76e4c31 100644 --- a/bdk/libs/nx_savedata/header.h +++ b/bdk/libs/nx_savedata/header.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/bdk/libs/nx_savedata/remap_storage.h b/bdk/libs/nx_savedata/remap_storage.h index 2917775..fc048a3 100644 --- a/bdk/libs/nx_savedata/remap_storage.h +++ b/bdk/libs/nx_savedata/remap_storage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/bdk/libs/nx_savedata/save_fs_list.h b/bdk/libs/nx_savedata/save_fs_list.h index 72b4e4b..da98736 100644 --- a/bdk/libs/nx_savedata/save_fs_list.h +++ b/bdk/libs/nx_savedata/save_fs_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/bdk/utils/util.c b/bdk/utils/util.c index 1fae04e..bf30929 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer +# Copyright (c) 2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index bff4f9b..a11ba7a 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/keys/keys.c b/source/keys/keys.c index 5604180..1f26f53 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/keys/keys.h b/source/keys/keys.h index 3a61684..6850e07 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 shchmue + * Copyright (c) 2019-2022 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/source/storage/nx_emmc_bis.h b/source/storage/nx_emmc_bis.h index a1cfaa6..f207acd 100644 --- a/source/storage/nx_emmc_bis.h +++ b/source/storage/nx_emmc_bis.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2022 shchmue * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it From cbab1ec5b0207327d9fed497d85824a3045681de Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 31 Oct 2022 20:20:13 -0700 Subject: [PATCH 156/166] keys: Make code more readable --- source/keys/gmac.c | 130 ++++++++++++++++++ source/keys/gmac.h | 24 ++++ source/keys/keys.c | 333 +++++++++++++++++---------------------------- source/keys/keys.h | 15 +- 4 files changed, 287 insertions(+), 215 deletions(-) create mode 100644 source/keys/gmac.c create mode 100644 source/keys/gmac.h diff --git a/source/keys/gmac.c b/source/keys/gmac.c new file mode 100644 index 0000000..0749411 --- /dev/null +++ b/source/keys/gmac.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * Copyright (c) 2019-2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gmac.h" + +#include +#include + +#include +#include + +/* Shifts right a little endian 128-bit value. */ +static void _shr_128(uint64_t *val) { + val[0] >>= 1; + val[0] |= (val[1] & 1) << 63; + val[1] >>= 1; +} + +/* Shifts left a little endian 128-bit value. */ +static void _shl_128(uint64_t *val) { + val[1] <<= 1; + val[1] |= (val[0] & (1ull << 63)) >> 63; + val[0] <<= 1; +} + +/* Multiplies two 128-bit numbers X,Y in the GF(128) Galois Field. */ +static void _gf128_mul(uint8_t *dst, const uint8_t *x, const uint8_t *y) { + uint8_t x_work[0x10]; + uint8_t y_work[0x10]; + uint8_t dst_work[0x10]; + + uint64_t *p_x = (uint64_t *)(&x_work[0]); + uint64_t *p_y = (uint64_t *)(&y_work[0]); + uint64_t *p_dst = (uint64_t *)(&dst_work[0]); + + /* Initialize buffers. */ + for (unsigned int i = 0; i < 0x10; i++) { + x_work[i] = x[0xF-i]; + y_work[i] = y[0xF-i]; + dst_work[i] = 0; + } + + /* Perform operation for each bit in y. */ + for (unsigned int round = 0; round < 0x80; round++) { + p_dst[0] ^= p_x[0] * ((y_work[0xF] & 0x80) >> 7); + p_dst[1] ^= p_x[1] * ((y_work[0xF] & 0x80) >> 7); + _shl_128(p_y); + uint8_t xval = 0xE1 * (x_work[0] & 1); + _shr_128(p_x); + x_work[0xF] ^= xval; + } + + for (unsigned int i = 0; i < 0x10; i++) { + dst[i] = dst_work[0xF-i]; + } +} + +static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt) { + uint8_t x[0x10] = {0}; + uint8_t h[0x10]; + + uint64_t *p_x = (uint64_t *)(&x[0]); + uint64_t *p_data = (uint64_t *)src; + + /* H = aes_ecb_encrypt(zeroes) */ + se_aes_crypt_block_ecb(ks, ENCRYPT, h, x); + + u64 total_size = src_size; + + while (src_size >= 0x10) { + /* X = (X ^ current_block) * H */ + p_x[0] ^= p_data[0]; + p_x[1] ^= p_data[1]; + _gf128_mul(x, x, h); + + /* Increment p_data by 0x10 bytes. */ + p_data += 2; + src_size -= 0x10; + } + + /* Nintendo's code *discards all data in the last block* if unaligned. */ + /* And treats that block as though it were all-zero. */ + /* This is a bug, they just forget to XOR with the copy of the last block they save. */ + if (src_size & 0xF) { + _gf128_mul(x, x, h); + } + + uint64_t xor_size = total_size << 3; + xor_size = __builtin_bswap64(xor_size); + + /* Due to a Nintendo bug, the wrong QWORD gets XOR'd in the "final output block" case. */ + if (encrypt) { + p_x[0] ^= xor_size; + } else { + p_x[1] ^= xor_size; + } + + _gf128_mul(x, x, h); + + /* If final output block, XOR with encrypted J block. */ + if (encrypt) { + se_aes_crypt_block_ecb(ks, ENCRYPT, h, j_block); + for (unsigned int i = 0; i < 0x10; i++) { + x[i] ^= h[i]; + } + } + /* Copy output. */ + memcpy(dst, x, 0x10); +} + +void _calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv) { + u32 j_block[4] = {0}; + se_aes_key_set(ks, key, 0x10); + _ghash(ks, j_block, iv, 0x10, NULL, false); + _ghash(ks, out_gmac, data, size, j_block, true); +} diff --git a/source/keys/gmac.h b/source/keys/gmac.h new file mode 100644 index 0000000..b97b4af --- /dev/null +++ b/source/keys/gmac.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GMAC_H_ +#define _GMAC_H_ + +#include + +void _calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv); + +#endif diff --git a/source/keys/keys.c b/source/keys/keys.c index 1f26f53..414a320 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -16,6 +16,8 @@ #include "keys.h" +#include "gmac.h" + #include "../../keygen/tsec_keygen.h" #include "../config.h" @@ -25,6 +27,7 @@ #include "../gfx/tui.h" #include "../hos/hos.h" #include +#include #include #include #include @@ -80,7 +83,6 @@ static void _get_device_unique_data_key(u32 ks, void *out_key, const void *acces static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation, u32 option); static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation); static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation); -static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt); // titlekey functions static bool _test_rsa_keypair(const void *E, const void *D, const void *N); @@ -206,7 +208,7 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { } _generate_specific_aes_key(KS_AES_ECB, keys, &keys->bis_key[0], bis_key_sources[0], generation); u32 access_key[AES_128_KEY_SIZE / 4] = {0}; - const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); + const u32 option = IS_DEVICE_UNIQUE; _generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); @@ -222,14 +224,7 @@ static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { } } -static void _derive_eticket_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kek_source, u32 generation, u32 option) { - void *access_key = keys->temp_key; - _generate_aes_kek(ks, keys, access_key, eticket_rsa_kekek_source, generation, option); - _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); - -} - -static void _derive_ssl_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { +static void _derive_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { void *access_key = keys->temp_key; _generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); @@ -239,7 +234,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { void *access_key = keys->temp_key; const u32 generation = 0; - const u32 option = GET_IS_DEVICE_UNIQUE(IS_DEVICE_UNIQUE); + const u32 option = IS_DEVICE_UNIQUE; _generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); _load_aes_key(KS_AES_ECB, keys->save_mac_key, access_key, save_mac_key_source); } @@ -247,12 +242,12 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { const void *eticket_kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; const u32 generation = 0; - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); - _derive_eticket_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek, eticket_kek_source, generation, option); + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; + _derive_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek, eticket_rsa_kekek_source, eticket_kek_source, generation, option); const void *ssl_kek_source = is_dev ? ssl_rsa_kek_source_dev : ssl_rsa_kek_source; - option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); - _derive_ssl_rsa_kek(KS_AES_ECB, keys, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); + option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; + _derive_rsa_kek(KS_AES_ECB, keys, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); } } @@ -440,10 +435,11 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { } u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; - for (u32 i = SZ_32K; i < f_size(&fp); i += SZ_16K) { + // Skip the two header blocks and only check the first bytes of each block - file contents are always block-aligned + for (u32 i = SAVE_BLOCK_SIZE_DEFAULT * 2; i < f_size(&fp); i += SAVE_BLOCK_SIZE_DEFAULT) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; - if (!memcmp(keys->temp_key, read_buf, sizeof(keys->temp_key))) { + if (memcmp(keys->temp_key, read_buf, sizeof(keys->temp_key)) == 0) { memcpy(keys->sd_seed, read_buf + 0x10, sizeof(keys->sd_seed)); break; } @@ -456,14 +452,20 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { } static bool _read_cal0(void *read_buffer) { + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)read_buffer; + + // Check if CAL0 was already read into this buffer + if (cal0->magic == MAGIC_CAL0) { + return true; + } + if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, read_buffer)) { EPRINTF("Unable to read PRODINFO."); return false; } - se_aes_xts_crypt(1, 0, DECRYPT, 0, read_buffer, read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); + se_aes_xts_crypt(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, DECRYPT, 0, read_buffer, read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)read_buffer; if (cal0->magic != MAGIC_CAL0) { EPRINTF("Invalid CAL0 magic. Check BIS key 0."); return false; @@ -472,7 +474,7 @@ static bool _read_cal0(void *read_buffer) { return true; } -static bool _get_rsa_ssl_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { +static bool _cal0_read_ssl_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { const u32 ext_key_size = sizeof(cal0->ext_ssl_key_iv) + sizeof(cal0->ext_ssl_key); const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ssl_key_ver) + sizeof(cal0->crc16_pad39); const u32 key_size = sizeof(cal0->ssl_key_iv) + sizeof(cal0->ssl_key); @@ -495,27 +497,27 @@ static bool _get_rsa_ssl_key(const nx_emmc_cal0_t *cal0, const void **out_key, u return true; } -static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { +static bool _decrypt_ssl_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { if (!_read_cal0(titlekey_buffer->read_buffer)) { return false; } nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; u32 generation = 0; - const void *ssl_device_key = NULL; - const void *ssl_iv = NULL; + const void *encrypted_key = NULL; + const void *iv = NULL; u32 key_size = 0; void *keypair_ctr_key = NULL; bool enforce_unique = true; - if (!_get_rsa_ssl_key(cal0, &ssl_device_key, &key_size, &ssl_iv, &generation)) { + if (!_cal0_read_ssl_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { EPRINTF("Crc16 error reading device key."); return false; } if (key_size == SSL_RSA_KEY_SIZE) { bool all_zero = true; - const u8 *key8 = (const u8 *)ssl_device_key; + const u8 *key8 = (const u8 *)encrypted_key; for (u32 i = RSA_2048_KEY_SIZE; i < SSL_RSA_KEY_SIZE; i++) { if (key8[i] != 0) { all_zero = false; @@ -523,38 +525,32 @@ static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_bu } } if (all_zero) { - // Keypairs of this form are not encrypted - memcpy(keys->ssl_rsa_key, ssl_device_key, RSA_2048_KEY_SIZE); + // Keys of this form are not encrypted + memcpy(keys->ssl_rsa_key, encrypted_key, RSA_2048_KEY_SIZE); return true; } - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA); + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; keypair_ctr_key = keys->ssl_rsa_kek_legacy; - _derive_ssl_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); + _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); enforce_unique = false; - } - - if (generation) { - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; + } else if (generation) { + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; keypair_ctr_key = keys->ssl_rsa_kek_personalized; - _derive_ssl_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); + _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); } else { keypair_ctr_key = keys->ssl_rsa_kek; } u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, ssl_device_key, ctr_size, ssl_iv); + se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, encrypted_key, ctr_size, iv); if (enforce_unique) { - u32 j_block[AES_128_KEY_SIZE / 4] = {0}; - se_aes_key_set(KS_AES_ECB, keypair_ctr_key, AES_128_KEY_SIZE); - _ghash(KS_AES_ECB, j_block, ssl_iv, 0x10, NULL, false); - u32 calc_mac[AES_128_KEY_SIZE / 4] = {0}; - _ghash(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, j_block, true); + _calc_gmac(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, keypair_ctr_key, iv); - const u8 *key8 = (const u8 *)ssl_device_key; + const u8 *key8 = (const u8 *)encrypted_key; if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { EPRINTF("SSL keypair has invalid GMac."); memset(keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); @@ -565,7 +561,7 @@ static bool _derive_personalized_ssl_key(key_derivation_ctx_t *keys, titlekey_bu return true; } -static bool _get_rsa_eticket_key(const nx_emmc_cal0_t *cal0, const void **out_key, const void **out_iv, u32 *out_generation) { +static bool _cal0_read_eticket_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { const u32 ext_key_size = sizeof(cal0->ext_ecc_rsa2048_eticket_key_iv) + sizeof(cal0->ext_ecc_rsa2048_eticket_key); const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ecc_rsa2048_eticket_key_ver) + sizeof(cal0->crc16_pad38); const u32 key_size = sizeof(cal0->rsa2048_eticket_key_iv) + sizeof(cal0->rsa2048_eticket_key); @@ -573,11 +569,13 @@ static bool _get_rsa_eticket_key(const nx_emmc_cal0_t *cal0, const void **out_ke if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, ext_key_crc_size)) { *out_key = cal0->ext_ecc_rsa2048_eticket_key; + *out_key_size = ext_key_size; *out_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; // Settings sysmodule manually zeroes this out below cal version 9 *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, key_crc_size)) { *out_key = cal0->rsa2048_eticket_key; + *out_key_size = key_size; *out_iv = cal0->rsa2048_eticket_key_iv; *out_generation = 0; } else { @@ -586,6 +584,70 @@ static bool _get_rsa_eticket_key(const nx_emmc_cal0_t *cal0, const void **out_ke return true; } +static bool _test_eticket_rsa_keypair(const rsa_keypair_t *keypair) { + // Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent + // and test the keypair since we have the modulus + if ((_read_be_u32(keypair->public_exponent, 0) != RSA_PUBLIC_EXPONENT) || + (!_test_rsa_keypair(keypair->public_exponent, keypair->private_exponent, keypair->modulus))) { + return false; + } + return true; +} + +static bool _decrypt_eticket_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { + if (!_read_cal0(titlekey_buffer->read_buffer)) { + return false; + } + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; + u32 generation = 0; + const void *encrypted_key = NULL; + const void *iv = NULL; + u32 key_size = 0; + void *keypair_ctr_key = NULL; + + if (!_cal0_read_eticket_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { + EPRINTF("Crc16 error reading device key."); + return false; + } + + // Handle legacy case + if (key_size == ETICKET_RSA_KEYPAIR_SIZE) { + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; + keypair_ctr_key = keys->temp_key; + _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kekek_source, eticket_rsa_kek_source_legacy, generation, option); + + se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); + + if (_test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + memcpy(keys->eticket_rsa_kek, keypair_ctr_key, sizeof(keys->eticket_rsa_kek)); + return true; + } + // Fall through and try usual method if not applicable + } + + if (generation) { + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; + keypair_ctr_key = keys->eticket_rsa_kek_personalized; + const void *kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; + _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kekek_source, kek_source, generation, option); + } else { + keypair_ctr_key = keys->eticket_rsa_kek; + } + + se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); + + if (!_test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + EPRINTF("Invalid eticket keypair."); + memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); + return false; + } + + return true; +} + static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { if (!_key_exists(keys->eticket_rsa_kek)) { return false; @@ -593,57 +655,11 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - if (!_read_cal0(titlekey_buffer->read_buffer)) { + if (!_decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev)) { return false; } - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - u32 generation = 0; - const void *eticket_device_key = NULL; - const void *eticket_iv = NULL; - void *keypair_ctr_key = NULL; - - if (!_get_rsa_eticket_key(cal0, &eticket_device_key, &eticket_iv, &generation)) { - EPRINTF("Crc16 error reading device key."); - return false; - } - - if (generation) { - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; - _derive_eticket_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek_personalized, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source, generation, option); - keypair_ctr_key = keys->eticket_rsa_kek_personalized; - } else { - keypair_ctr_key = keys->eticket_rsa_kek; - } - - se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); - - if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { - // Try legacy kek source - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY); - keypair_ctr_key = keys->temp_key; - _derive_eticket_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kek_source_legacy, 0, option); - - se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), eticket_device_key, sizeof(keys->eticket_rsa_keypair), eticket_iv); - - if (_read_be_u32(keys->eticket_rsa_keypair.public_exponent, 0) != RSA_PUBLIC_EXPONENT) { - EPRINTF("Invalid public exponent."); - memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); - return false; - } else { - memcpy(keys->eticket_rsa_kek, keys->temp_key, sizeof(keys->eticket_rsa_kek)); - } - } - - if (!_test_rsa_keypair(keys->eticket_rsa_keypair.public_exponent, keys->eticket_rsa_keypair.private_exponent, keys->eticket_rsa_keypair.modulus)) { - EPRINTF("Invalid keypair. Check eticket_rsa_kek."); - memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); - return false; - } - - const u32 buf_size = SZ_16K; + const u32 buf_size = SAVE_BLOCK_SIZE_DEFAULT; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &keys->eticket_rsa_keypair); @@ -655,14 +671,14 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { // Set BIS keys. // PRODINFO/PRODINFOF - se_aes_key_set(KS_BIS_00_0, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_00_1, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_00_CRYPT, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_00_TWEAK, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); // SAFE - se_aes_key_set(KS_BIS_01_0, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_01_1, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_01_CRYPT, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_01_TWEAK, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); // SYSTEM/USER - se_aes_key_set(KS_BIS_02_0, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_02_1, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_02_CRYPT, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_02_TWEAK, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); if (!emummc_storage_set_mmc_partition(EMMC_GPP)) { EPRINTF("Unable to set partition."); @@ -693,13 +709,16 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit EPRINTF("Unable to get SD seed."); } - bool res = _derive_titlekeys(keys, titlekey_buffer, is_dev); + bool res = _decrypt_ssl_rsa_key(keys, titlekey_buffer); + if (!res) { + EPRINTF("Unable to derive SSL key."); + } + + res = _derive_titlekeys(keys, titlekey_buffer, is_dev); if (!res) { EPRINTF("Unable to derive titlekeys."); } - _derive_personalized_ssl_key(keys, titlekey_buffer); - f_mount(NULL, "bis:", 1); nx_emmc_gpt_free(&gpt); @@ -1194,7 +1213,7 @@ static void _generate_aes_kek(u32 ks, key_derivation_ctx_t *keys, void *out_kek, if (generation) generation--; - u8 static_source[AES_128_KEY_SIZE]; + u8 static_source[AES_128_KEY_SIZE] __attribute__((aligned(4))); for (u32 i = 0; i < AES_128_KEY_SIZE; i++) static_source[i] = aes_kek_generation_source[i] ^ seal_key_masks[seal_key_index][i]; @@ -1250,7 +1269,7 @@ static void _get_secure_data(key_derivation_ctx_t *keys, void *out_data) { // Equivalent to spl::GenerateSpecificAesKey static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation) { if (fuse_read_bootrom_rev() >= 0x7F) { - _get_device_key(ks, keys, keys->temp_key, generation - 1); + _get_device_key(ks, keys, keys->temp_key, generation == 0 ? 0 : generation - 1); se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); @@ -1278,114 +1297,12 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key_source); } -// The following ghash implementation is from Atmosphère's original exosphere implementation - -/* Shifts right a little endian 128-bit value. */ -static void _shr_128(uint64_t *val) { - val[0] >>= 1; - val[0] |= (val[1] & 1) << 63; - val[1] >>= 1; -} - -/* Shifts left a little endian 128-bit value. */ -static void _shl_128(uint64_t *val) { - val[1] <<= 1; - val[1] |= (val[0] & (1ull << 63)) >> 63; - val[0] <<= 1; -} - -/* Multiplies two 128-bit numbers X,Y in the GF(128) Galois Field. */ -static void _gf128_mul(uint8_t *dst, const uint8_t *x, const uint8_t *y) { - uint8_t x_work[0x10]; - uint8_t y_work[0x10]; - uint8_t dst_work[0x10]; - - uint64_t *p_x = (uint64_t *)(&x_work[0]); - uint64_t *p_y = (uint64_t *)(&y_work[0]); - uint64_t *p_dst = (uint64_t *)(&dst_work[0]); - - /* Initialize buffers. */ - for (unsigned int i = 0; i < 0x10; i++) { - x_work[i] = x[0xF-i]; - y_work[i] = y[0xF-i]; - dst_work[i] = 0; - } - - /* Perform operation for each bit in y. */ - for (unsigned int round = 0; round < 0x80; round++) { - p_dst[0] ^= p_x[0] * ((y_work[0xF] & 0x80) >> 7); - p_dst[1] ^= p_x[1] * ((y_work[0xF] & 0x80) >> 7); - _shl_128(p_y); - uint8_t xval = 0xE1 * (x_work[0] & 1); - _shr_128(p_x); - x_work[0xF] ^= xval; - } - - for (unsigned int i = 0; i < 0x10; i++) { - dst[i] = dst_work[0xF-i]; - } -} - -static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void *j_block, bool encrypt) { - uint8_t x[0x10] = {0}; - uint8_t h[0x10]; - - uint64_t *p_x = (uint64_t *)(&x[0]); - uint64_t *p_data = (uint64_t *)src; - - /* H = aes_ecb_encrypt(zeroes) */ - se_aes_crypt_block_ecb(ks, ENCRYPT, h, x); - - u64 total_size = src_size; - - while (src_size >= 0x10) { - /* X = (X ^ current_block) * H */ - p_x[0] ^= p_data[0]; - p_x[1] ^= p_data[1]; - _gf128_mul(x, x, h); - - /* Increment p_data by 0x10 bytes. */ - p_data += 2; - src_size -= 0x10; - } - - /* Nintendo's code *discards all data in the last block* if unaligned. */ - /* And treats that block as though it were all-zero. */ - /* This is a bug, they just forget to XOR with the copy of the last block they save. */ - if (src_size & 0xF) { - _gf128_mul(x, x, h); - } - - uint64_t xor_size = total_size << 3; - xor_size = __builtin_bswap64(xor_size); - - /* Due to a Nintendo bug, the wrong QWORD gets XOR'd in the "final output block" case. */ - if (encrypt) { - p_x[0] ^= xor_size; - } else { - p_x[1] ^= xor_size; - } - - _gf128_mul(x, x, h); - - /* If final output block, XOR with encrypted J block. */ - if (encrypt) { - se_aes_crypt_block_ecb(ks, ENCRYPT, h, j_block); - for (unsigned int i = 0; i < 0x10; i++) { - x[i] ^= h[i]; - } - } - /* Copy output. */ - memcpy(dst, x, 0x10); -} - static bool _test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus) { - u8 plaintext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, - ciphertext[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}, - work[RSA_2048_KEY_SIZE] __attribute__((aligned(4))) = {0}; + u32 plaintext[RSA_2048_KEY_SIZE / 4] = {0}, + ciphertext[RSA_2048_KEY_SIZE / 4] = {0}, + work[RSA_2048_KEY_SIZE / 4] = {0}; - // 0xCAFEBABE - plaintext[0xfc] = 0xca; plaintext[0xfd] = 0xfe; plaintext[0xfe] = 0xba; plaintext[0xff] = 0xbe; + plaintext[63] = 0xCAFEBABE; se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, private_exponent, RSA_2048_KEY_SIZE); se_rsa_exp_mod(0, ciphertext, RSA_2048_KEY_SIZE, plaintext, RSA_2048_KEY_SIZE); @@ -1393,5 +1310,5 @@ static bool _test_rsa_keypair(const void *public_exponent, const void *private_e se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, public_exponent, 4); se_rsa_exp_mod(0, work, RSA_2048_KEY_SIZE, ciphertext, RSA_2048_KEY_SIZE); - return !memcmp(plaintext, work, RSA_2048_KEY_SIZE); + return memcmp(plaintext, work, RSA_2048_KEY_SIZE) == 0; } diff --git a/source/keys/keys.h b/source/keys/keys.h index 6850e07..bb1b5af 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -27,12 +27,12 @@ #define RSA_PUBLIC_EXPONENT 65537 // Lockpick_RCM keyslots -#define KS_BIS_00_0 0 -#define KS_BIS_00_1 1 -#define KS_BIS_01_0 2 -#define KS_BIS_01_1 3 -#define KS_BIS_02_0 4 -#define KS_BIS_02_1 5 +#define KS_BIS_00_CRYPT 0 +#define KS_BIS_00_TWEAK 1 +#define KS_BIS_01_CRYPT 2 +#define KS_BIS_01_TWEAK 3 +#define KS_BIS_02_CRYPT 4 +#define KS_BIS_02_TWEAK 5 #define KS_AES_CTR 6 #define KS_AES_ECB 8 #define KS_AES_CMAC 10 @@ -148,7 +148,8 @@ typedef enum { #define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) #define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) -#define SSL_RSA_KEY_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) +#define SSL_RSA_KEY_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) +#define ETICKET_RSA_KEYPAIR_SIZE (RSA_2048_KEY_SIZE * 2 + AES_128_KEY_SIZE * 2) typedef struct { u8 temp_key[AES_128_KEY_SIZE], From cc4f8bf1f66e926329384f198f43781faba265e0 Mon Sep 17 00:00:00 2001 From: shchmue Date: Mon, 31 Oct 2022 21:46:38 -0700 Subject: [PATCH 157/166] keys: Move more logic out of keys.c --- bdk/utils/util.c | 14 ++ bdk/utils/util.h | 2 + source/keys/cal0_read.c | 96 +++++++++ source/keys/cal0_read.h | 27 +++ source/keys/crypto.c | 146 +++++++++++++ source/keys/crypto.h | 223 +++++++++++++++++++ source/keys/gmac.c | 2 +- source/keys/gmac.h | 2 +- source/keys/key_sources.inl | 72 ------- source/keys/keys.c | 411 +++++++++--------------------------- source/keys/keys.h | 111 +--------- 11 files changed, 615 insertions(+), 491 deletions(-) create mode 100644 source/keys/cal0_read.c create mode 100644 source/keys/cal0_read.h create mode 100644 source/keys/crypto.c create mode 100644 source/keys/crypto.h diff --git a/bdk/utils/util.c b/bdk/utils/util.c index bf30929..e05c2bc 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -230,3 +230,17 @@ void power_set_state_ex(void *param) power_state_t *state = (power_state_t *)param; power_set_state(*state); } + +u32 read_le_u32(const void *buffer, u32 offset) { + return (*(u8*)(buffer + offset + 0) ) | + (*(u8*)(buffer + offset + 1) << 0x08) | + (*(u8*)(buffer + offset + 2) << 0x10) | + (*(u8*)(buffer + offset + 3) << 0x18); +} + +u32 read_be_u32(const void *buffer, u32 offset) { + return (*(u8*)(buffer + offset + 3) ) | + (*(u8*)(buffer + offset + 2) << 0x08) | + (*(u8*)(buffer + offset + 1) << 0x10) | + (*(u8*)(buffer + offset + 0) << 0x18); +} diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 972a906..df929bc 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -96,5 +96,7 @@ void panic(u32 val); void power_set_state(power_state_t state); void power_set_state_ex(void *param); +u32 read_le_u32(const void *buffer, u32 offset); +u32 read_be_u32(const void *buffer, u32 offset); #endif diff --git a/source/keys/cal0_read.c b/source/keys/cal0_read.c new file mode 100644 index 0000000..9b0c4fd --- /dev/null +++ b/source/keys/cal0_read.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cal0_read.h" + +#include +#include +#include +#include "../storage/emummc.h" +#include "../storage/nx_emmc.h" +#include + +bool cal0_read(u32 tweak_ks, u32 crypt_ks, void *read_buffer) { + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)read_buffer; + + // Check if CAL0 was already read into this buffer + if (cal0->magic == MAGIC_CAL0) { + return true; + } + + if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, read_buffer)) { + EPRINTF("Unable to read PRODINFO."); + return false; + } + + se_aes_xts_crypt(tweak_ks, crypt_ks, DECRYPT, 0, read_buffer, read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); + + if (cal0->magic != MAGIC_CAL0) { + EPRINTF("Invalid CAL0 magic. Check BIS key 0."); + return false; + } + + return true; +} + +bool cal0_get_ssl_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { + const u32 ext_key_size = sizeof(cal0->ext_ssl_key_iv) + sizeof(cal0->ext_ssl_key); + const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ssl_key_ver) + sizeof(cal0->crc16_pad39); + const u32 key_size = sizeof(cal0->ssl_key_iv) + sizeof(cal0->ssl_key); + const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad18); + + if (cal0->ext_ssl_key_crc == crc16_calc(cal0->ext_ssl_key_iv, ext_key_crc_size)) { + *out_key = cal0->ext_ssl_key; + *out_key_size = ext_key_size; + *out_iv = cal0->ext_ssl_key_iv; + // Settings sysmodule manually zeroes this out below cal version 9 + *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; + } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, key_crc_size)) { + *out_key = cal0->ssl_key; + *out_key_size = key_size; + *out_iv = cal0->ssl_key_iv; + *out_generation = 0; + } else { + EPRINTF("Crc16 error reading device key."); + return false; + } + return true; +} + + +bool cal0_get_eticket_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { + const u32 ext_key_size = sizeof(cal0->ext_ecc_rsa2048_eticket_key_iv) + sizeof(cal0->ext_ecc_rsa2048_eticket_key); + const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ecc_rsa2048_eticket_key_ver) + sizeof(cal0->crc16_pad38); + const u32 key_size = sizeof(cal0->rsa2048_eticket_key_iv) + sizeof(cal0->rsa2048_eticket_key); + const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad21); + + if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, ext_key_crc_size)) { + *out_key = cal0->ext_ecc_rsa2048_eticket_key; + *out_key_size = ext_key_size; + *out_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; + // Settings sysmodule manually zeroes this out below cal version 9 + *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; + } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, key_crc_size)) { + *out_key = cal0->rsa2048_eticket_key; + *out_key_size = key_size; + *out_iv = cal0->rsa2048_eticket_key_iv; + *out_generation = 0; + } else { + EPRINTF("Crc16 error reading device key."); + return false; + } + return true; +} diff --git a/source/keys/cal0_read.h b/source/keys/cal0_read.h new file mode 100644 index 0000000..2ab1ae1 --- /dev/null +++ b/source/keys/cal0_read.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CAL0_READ_H_ +#define _CAL0_READ_H_ + +#include "../storage/nx_emmc_bis.h" +#include + +bool cal0_read(u32 tweak_ks, u32 crypt_ks, void *read_buffer); +bool cal0_get_ssl_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation); +bool cal0_get_eticket_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation); + +#endif diff --git a/source/keys/crypto.c b/source/keys/crypto.c new file mode 100644 index 0000000..cd5afd0 --- /dev/null +++ b/source/keys/crypto.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "crypto.h" + +#include "../config.h" +#include "../hos/hos.h" +#include +#include +#include +#include + +#include + +extern hekate_config h_cfg; + +bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus) { + u32 plaintext[SE_RSA2048_DIGEST_SIZE / 4] = {0}, + ciphertext[SE_RSA2048_DIGEST_SIZE / 4] = {0}, + work[SE_RSA2048_DIGEST_SIZE / 4] = {0}; + + plaintext[63] = 0xCAFEBABE; + + se_rsa_key_set(0, modulus, SE_RSA2048_DIGEST_SIZE, private_exponent, SE_RSA2048_DIGEST_SIZE); + se_rsa_exp_mod(0, ciphertext, SE_RSA2048_DIGEST_SIZE, plaintext, SE_RSA2048_DIGEST_SIZE); + + se_rsa_key_set(0, modulus, SE_RSA2048_DIGEST_SIZE, public_exponent, 4); + se_rsa_exp_mod(0, work, SE_RSA2048_DIGEST_SIZE, ciphertext, SE_RSA2048_DIGEST_SIZE); + + return memcmp(plaintext, work, SE_RSA2048_DIGEST_SIZE) == 0; +} + +bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair) { + // Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent + // and test the keypair since we have the modulus + if ((read_be_u32(keypair->public_exponent, 0) != RSA_PUBLIC_EXPONENT) || + (!test_rsa_keypair(keypair->public_exponent, keypair->private_exponent, keypair->modulus))) { + return false; + } + return true; +} + +// Equivalent to spl::GenerateAesKek +void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option) { + bool device_unique = GET_IS_DEVICE_UNIQUE(option); + u32 seal_key_index = GET_SEAL_KEY_INDEX(option); + + if (generation) + generation--; + + u8 static_source[SE_KEY_128_SIZE] __attribute__((aligned(4))); + for (u32 i = 0; i < SE_KEY_128_SIZE; i++) + static_source[i] = aes_kek_generation_source[i] ^ seal_key_masks[seal_key_index][i]; + + if (device_unique) { + get_device_key(ks, keys, keys->temp_key, generation); + } else { + memcpy(keys->temp_key, keys->master_key[generation], sizeof(keys->temp_key)); + } + se_aes_key_set(ks, keys->temp_key, SE_KEY_128_SIZE); + se_aes_unwrap_key(ks, ks, static_source); + se_aes_crypt_block_ecb(ks, DECRYPT, out_kek, kek_source); +} + +// Based on spl::LoadAesKey but instead of prepping keyslot, returns calculated key +void load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { + se_aes_key_set(ks, access_key, SE_KEY_128_SIZE); + se_aes_crypt_block_ecb(ks, DECRYPT, out_key, key_source); +} + +// Equivalent to spl::GenerateAesKey +void generate_aes_key(u32 ks, key_storage_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source) { + void *aes_key = keys->temp_key; + load_aes_key(ks, aes_key, access_key, aes_key_generation_source); + se_aes_key_set(ks, aes_key, SE_KEY_128_SIZE); + se_aes_crypt_ecb(ks, DECRYPT, out_key, key_size, key_source, key_size); +} + +// Equivalent to smc::PrepareDeviceUniqueDataKey but with no sealing +void get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { + load_aes_key(ks, out_key, access_key, key_source); +} + +// Equivalent to spl::DecryptAesKey. +void decrypt_aes_key(u32 ks, key_storage_t *keys, void *out_key, const void *key_source, u32 generation, u32 option) { + void *access_key = keys->temp_key; + generate_aes_kek(ks, keys, access_key, aes_key_decryption_source, generation, option); + generate_aes_key(ks, keys, out_key, SE_KEY_128_SIZE, access_key, key_source); +} + +// Equivalent to smc::GetSecureData +void get_secure_data(key_storage_t *keys, void *out_data) { + se_aes_key_set(KS_AES_CTR, keys->device_key, SE_KEY_128_SIZE); + u8 *d = (u8 *)out_data; + se_aes_crypt_ctr(KS_AES_CTR, d + SE_KEY_128_SIZE * 0, SE_KEY_128_SIZE, secure_data_source, SE_KEY_128_SIZE, secure_data_counters[0]); + se_aes_crypt_ctr(KS_AES_CTR, d + SE_KEY_128_SIZE * 1, SE_KEY_128_SIZE, secure_data_source, SE_KEY_128_SIZE, secure_data_counters[0]); + + // Apply tweak + for (u32 i = 0; i < SE_KEY_128_SIZE; i++) { + d[SE_KEY_128_SIZE + i] ^= secure_data_tweaks[0][i]; + } +} + +// Equivalent to spl::GenerateSpecificAesKey +void generate_specific_aes_key(u32 ks, key_storage_t *keys, void *out_key, const void *key_source, u32 generation) { + if (fuse_read_bootrom_rev() >= 0x7F) { + get_device_key(ks, keys, keys->temp_key, generation == 0 ? 0 : generation - 1); + se_aes_key_set(ks, keys->temp_key, SE_KEY_128_SIZE); + se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); + se_aes_crypt_ecb(ks, DECRYPT, out_key, SE_KEY_128_SIZE * 2, key_source, SE_KEY_128_SIZE * 2); + } else { + get_secure_data(keys, out_key); + } +} + +void get_device_key(u32 ks, key_storage_t *keys, void *out_device_key, u32 generation) { + if (generation == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) { + memcpy(out_device_key, keys->device_key, SE_KEY_128_SIZE); + return; + } + + if (generation >= KB_FIRMWARE_VERSION_400) { + generation -= KB_FIRMWARE_VERSION_400; + } else { + generation = 0; + } + u32 temp_key_source[SE_KEY_128_SIZE / 4] = {0}; + load_aes_key(ks, temp_key_source, keys->device_key_4x, device_master_key_source_sources[generation]); + const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[generation] : device_master_kek_sources_dev[generation]; + se_aes_key_set(ks, keys->master_key[0], SE_KEY_128_SIZE); + se_aes_unwrap_key(ks, ks, kek_source); + se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key_source); +} diff --git a/source/keys/crypto.h b/source/keys/crypto.h new file mode 100644 index 0000000..4e1d0d7 --- /dev/null +++ b/source/keys/crypto.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +#include "../hos/hos.h" +#include +#include + +static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { + 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; + +static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { + 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; + +static const u8 aes_key_decryption_source[0x10] __attribute__((aligned(4))) = { + 0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}; + +static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ + {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */ + {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */ + {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */ + {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ + {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ + {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ + {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ + {0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2}, /* 14.0.0 Device Master Kek Source. */ + {0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49}, /* 15.0.0 Device Master Kek Source. */ +}; //!TODO: Update on mkey changes. + +static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { + {0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */ + {0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */ + {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */ + {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */ + {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */ + {0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */ + {0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */ + {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ + {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ + {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ + {0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA}, /* 14.0.0 Device Master Kek Source. */ + {0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E}, /* 15.0.0 Device Master Kek Source. */ +}; //!TODO: Update on mkey changes. + +static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ + {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */ + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */ + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */ + {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ + {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ + {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ + {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ + {0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D}, /* 14.0.0 Device Master Key Source Source. */ + {0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6}, /* 15.0.0 Device Master Key Source Source. */ +}; //!TODO: Update on mkey changes. + +static const u8 seal_key_masks[][0x10] __attribute__((aligned(4))) = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // SealKey_LoadAesKey + {0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}, // SealKey_DecryptDeviceUniqueData + {0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C}, // SealKey_ImportLotusKey + {0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}, // SealKey_ImportEsDeviceKey + {0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31}, // SealKey_ReencryptDeviceUniqueData + {0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75}, // SealKey_ImportSslKey + {0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61}, // SealKey_ImportEsClientCertKey +}; + +static const u8 retail_specific_aes_key_source[0x10] __attribute__((aligned(4))) = { + 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; + +static const u8 secure_data_source[0x10] __attribute__((aligned(4))) = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const u8 secure_data_counters[1][0x10] __attribute__((aligned(4))) = { + {0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9} +}; + +static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { + {0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E} +}; + +// Lockpick_RCM keyslots +#define KS_BIS_00_CRYPT 0 +#define KS_BIS_00_TWEAK 1 +#define KS_BIS_01_CRYPT 2 +#define KS_BIS_01_TWEAK 3 +#define KS_BIS_02_CRYPT 4 +#define KS_BIS_02_TWEAK 5 +#define KS_AES_CTR 6 +#define KS_AES_ECB 8 +#define KS_AES_CMAC 10 + +// Mariko keyslots +#define KS_MARIKO_KEK 12 +#define KS_MARIKO_BEK 13 + +// Other Switch keyslots +#define KS_TSEC 12 +#define KS_SECURE_BOOT 14 + +// Atmosphere keygen keyslots +#define KS_TSEC_ROOT_DEV 11 +#define KS_TSEC_ROOT 13 + +#define RSA_PUBLIC_EXPONENT 65537 + +#define SSL_RSA_KEY_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE) +#define ETICKET_RSA_KEYPAIR_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE * 2 + SE_KEY_128_SIZE) + +typedef struct { + u8 private_exponent[SE_RSA2048_DIGEST_SIZE]; + u8 modulus[SE_RSA2048_DIGEST_SIZE]; + u8 public_exponent[4]; + u8 reserved[0xC]; +} rsa_keypair_t; + +typedef struct { + u8 master_kek[SE_KEY_128_SIZE]; + u8 data[0x70]; + u8 package1_key[SE_KEY_128_SIZE]; +} keyblob_t; + +typedef struct { + u8 cmac[0x10]; + u8 iv[0x10]; + keyblob_t key_data; + u8 unused[0x150]; +} encrypted_keyblob_t; + +typedef struct { + u8 temp_key[SE_KEY_128_SIZE], + bis_key[4][SE_KEY_128_SIZE * 2], + device_key[SE_KEY_128_SIZE], + device_key_4x[SE_KEY_128_SIZE], + sd_seed[SE_KEY_128_SIZE], + // FS-related keys + header_key[SE_KEY_128_SIZE * 2], + save_mac_key[SE_KEY_128_SIZE], + // other sysmodule keys + eticket_rsa_kek[SE_KEY_128_SIZE], + eticket_rsa_kek_personalized[SE_KEY_128_SIZE], + ssl_rsa_kek[SE_KEY_128_SIZE], + ssl_rsa_kek_legacy[SE_KEY_128_SIZE], + ssl_rsa_kek_personalized[SE_KEY_128_SIZE], + ssl_rsa_key[SE_RSA2048_DIGEST_SIZE + 0x20], + // keyblob-derived families + keyblob_key[KB_FIRMWARE_VERSION_600 + 1][SE_KEY_128_SIZE], + keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][SE_KEY_128_SIZE], + package1_key[KB_FIRMWARE_VERSION_600 + 1][SE_KEY_128_SIZE], + // master key-derived families + key_area_key[3][KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], + master_kek[KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], + master_key[KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], + package2_key[KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], + titlekek[KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], + tsec_key[SE_KEY_128_SIZE], + tsec_root_key[SE_KEY_128_SIZE]; + u32 sbk[4]; + keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; + rsa_keypair_t eticket_rsa_keypair; +} key_storage_t; + +typedef enum { + SEAL_KEY_LOAD_AES_KEY = 0, + SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA = 1, + SEAL_KEY_IMPORT_LOTUS_KEY = 2, + SEAL_KEY_IMPORT_ES_DEVICE_KEY = 3, + SEAL_KEY_REENCRYPT_DEVICE_UNIQUE_DATA = 4, + SEAL_KEY_IMPORT_SSL_KEY = 5, + SEAL_KEY_IMPORT_ES_CLIENT_CERT_KEY = 6, +} seal_key_t; + +typedef enum { + NOT_DEVICE_UNIQUE = 0, + IS_DEVICE_UNIQUE = 1, +} device_unique_t; + +#define SET_SEAL_KEY_INDEX(x) (((x) & 7) << 5) +#define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) +#define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) + +bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus); +bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair); + +// Equivalent to spl::GenerateAesKek +void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option); +// Equivalent to spl::GenerateAesKey +void generate_aes_key(u32 ks, key_storage_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source); +// Equivalent to spl::GenerateSpecificAesKey +void generate_specific_aes_key(u32 ks, key_storage_t *keys, void *out_key, const void *key_source, u32 generation); +// Equivalent to spl::DecryptAesKey. +void decrypt_aes_key(u32 ks, key_storage_t *keys, void *out_key, const void *key_source, u32 generation, u32 option); +// Based on spl::LoadAesKey but instead of prepping keyslot, returns calculated key +void load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source); + +// Equivalent to smc::PrepareDeviceUniqueDataKey but with no sealing +void get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source); +// Equivalent to smc::GetSecureData +void get_secure_data(key_storage_t *keys, void *out_data); +// Equivalent to smc::PrepareDeviceMasterKey +void get_device_key(u32 ks, key_storage_t *keys, void *out_device_key, u32 generation); + +#endif diff --git a/source/keys/gmac.c b/source/keys/gmac.c index 0749411..f8aea77 100644 --- a/source/keys/gmac.c +++ b/source/keys/gmac.c @@ -122,7 +122,7 @@ static void _ghash(u32 ks, void *dst, const void *src, u32 src_size, const void memcpy(dst, x, 0x10); } -void _calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv) { +void calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv) { u32 j_block[4] = {0}; se_aes_key_set(ks, key, 0x10); _ghash(ks, j_block, iv, 0x10, NULL, false); diff --git a/source/keys/gmac.h b/source/keys/gmac.h index b97b4af..98b7bdc 100644 --- a/source/keys/gmac.h +++ b/source/keys/gmac.h @@ -19,6 +19,6 @@ #include -void _calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv); +void calc_gmac(u32 ks, void *out_gmac, const void *data, u32 size, const void *key, const void *iv); #endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index a11ba7a..5d049f7 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -98,31 +98,10 @@ static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { //======================================Keys======================================// // from Package1 -> Secure_Monitor -static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { - 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 seal_key_masks[][0x10] __attribute__((aligned(4))) = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // SealKey_LoadAesKey - {0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}, // SealKey_DecryptDeviceUniqueData - {0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C}, // SealKey_ImportLotusKey - {0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}, // SealKey_ImportEsDeviceKey - {0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31}, // SealKey_ReencryptDeviceUniqueData - {0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75}, // SealKey_ImportSslKey - {0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61}, // SealKey_ImportEsClientCertKey -}; static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -static const u8 retail_specific_aes_key_source[0x10] __attribute__((aligned(4))) = { - 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; -static const u8 secure_data_source[0x10] __attribute__((aligned(4))) = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const u8 secure_data_counters[1][0x10] __attribute__((aligned(4))) = { - {0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9} -}; -static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { - {0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E} -}; // from Package1ldr (or Secure_Monitor on 6.2.0+) static const u8 keyblob_mac_key_source[0x10] __attribute__((aligned(4))) = { @@ -158,21 +137,6 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7}, // 15.0.0. }; //!TODO: Update on mkey changes. -static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */ - {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */ - {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */ - {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */ - {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */ - {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */ - {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */ - {0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */ - {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ - {0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D}, /* 14.0.0 Device Master Key Source Source. */ - {0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6}, /* 15.0.0 Device Master Key Source Source. */ -}; //!TODO: Update on mkey changes. - // from ES static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; @@ -197,42 +161,6 @@ static const u8 ssl_client_cert_kek_source[0x10] __attribute__((aligned(4))) = { static const u8 ssl_client_cert_key_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x92, 0x5A, 0x69, 0x42, 0x23, 0xBB, 0x92, 0x59, 0x16, 0x3E, 0x51, 0x8C, 0x78, 0x14, 0x0F}; -static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */ - {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */ - {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */ - {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */ - {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */ - {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */ - {0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */ - {0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */ - {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ - {0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2}, /* 14.0.0 Device Master Kek Source. */ - {0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49}, /* 15.0.0 Device Master Kek Source. */ -}; //!TODO: Update on mkey changes. - -static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { - {0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */ - {0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */ - {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */ - {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */ - {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */ - {0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */ - {0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */ - {0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */ - {0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */ - {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ - {0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA}, /* 14.0.0 Device Master Kek Source. */ - {0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E}, /* 15.0.0 Device Master Kek Source. */ -}; //!TODO: Update on mkey changes. - -// from SPL -static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { - 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; -static const u8 aes_key_decryption_source[0x10] __attribute__((aligned(4))) = { - 0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}; - // from FS static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; diff --git a/source/keys/keys.c b/source/keys/keys.c index 414a320..a53061e 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -16,6 +16,7 @@ #include "keys.h" +#include "cal0_read.h" #include "gmac.h" #include "../../keygen/tsec_keygen.h" @@ -58,46 +59,23 @@ static u32 _key_count = 0, _titlekey_count = 0; static u32 start_time, end_time; u32 color_idx = 0; -static ALWAYS_INLINE u32 _read_le_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 0) ) | - (*(u8*)(buffer + offset + 1) << 0x08) | - (*(u8*)(buffer + offset + 2) << 0x10) | - (*(u8*)(buffer + offset + 3) << 0x18); -} - -static ALWAYS_INLINE u32 _read_be_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 3) ) | - (*(u8*)(buffer + offset + 2) << 0x08) | - (*(u8*)(buffer + offset + 1) << 0x10) | - (*(u8*)(buffer + offset + 0) << 0x18); -} - // key functions static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; static void _save_key(const char *name, const void *data, u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); -static void _generate_aes_kek(u32 ks, key_derivation_ctx_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option); -static void _generate_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source); -static void _load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source); -static void _get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source); -static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation, u32 option); -static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation); -static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation); -// titlekey functions -static bool _test_rsa_keypair(const void *E, const void *D, const void *N); -static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) { +static void _derive_master_key_mariko(key_storage_t *keys, bool is_dev) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); // Derive all master keys based on Mariko KEK for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) { // Relies on the Mariko KEK being properly set in slot 12 se_aes_crypt_block_ecb(KS_MARIKO_KEK, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); - _load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); + load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } -static int _run_ams_keygen(key_derivation_ctx_t *keys) { +static int _run_ams_keygen(key_storage_t *keys) { tsec_ctxt_t tsec_ctxt; tsec_ctxt.fw = tsec_keygen; tsec_ctxt.size = sizeof(tsec_keygen); @@ -115,21 +93,21 @@ static int _run_ams_keygen(key_derivation_ctx_t *keys) { return 0; } -static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool is_dev) { +static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev) { if (!h_cfg.t210b01) { u32 tsec_root_key_slot = is_dev ? 11 : 13; // Derive all master keys based on current root key for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); - _load_aes_key(KS_AES_ECB, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); + load_aes_key(KS_AES_ECB, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); } } // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { - _load_aes_key(KS_AES_ECB, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); + load_aes_key(KS_AES_ECB, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); } - _load_aes_key(KS_AES_ECB, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); + load_aes_key(KS_AES_ECB, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); if (_key_exists(keys->temp_key)) { EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); @@ -137,15 +115,15 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool } } -static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { +static void _derive_keyblob_keys(key_storage_t *keys) { u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); - u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; + u32 keyblob_mac[SE_KEY_128_SIZE / 4] = {0}; bool have_keyblobs = true; if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); - se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); - memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); + memcpy(keys->sbk, aes_keys + 14 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); free(aes_keys); } else { keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); @@ -168,7 +146,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { minerva_periodic_training(); se_aes_crypt_block_ecb(KS_TSEC, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); - _load_aes_key(KS_AES_ECB, keys->keyblob_mac_key[i], keys->keyblob_key[i], keyblob_mac_key_source); + load_aes_key(KS_AES_ECB, keys->keyblob_mac_key[i], keys->keyblob_key[i], keyblob_mac_key_source); if (i == 0) { se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, keys->device_key, per_console_key_source); se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); @@ -193,50 +171,50 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { memcpy(keys->package1_key[i], keys->keyblob[i].package1_key, sizeof(keys->package1_key[i])); memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); if (!_key_exists(keys->master_key[i])) { - _load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); + load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } free(keyblob_block); } -static void _derive_bis_keys(key_derivation_ctx_t *keys) { +static void _derive_bis_keys(key_storage_t *keys) { minerva_periodic_training(); u32 generation = fuse_read_odm_keygen_rev(); if (!(_key_exists(keys->device_key) || (generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { return; } - _generate_specific_aes_key(KS_AES_ECB, keys, &keys->bis_key[0], bis_key_sources[0], generation); - u32 access_key[AES_128_KEY_SIZE / 4] = {0}; + generate_specific_aes_key(KS_AES_ECB, keys, &keys->bis_key[0], bis_key_sources[0], generation); + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; const u32 option = IS_DEVICE_UNIQUE; - _generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); - _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); - _generate_aes_key(KS_AES_ECB, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); + generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); + generate_aes_key(KS_AES_ECB, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); + generate_aes_key(KS_AES_ECB, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); memcpy(keys->bis_key[3], keys->bis_key[2], sizeof(keys->bis_key[3])); } -static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) { +static void _derive_non_unique_keys(key_storage_t *keys, bool is_dev) { if (_key_exists(keys->master_key[0])) { const u32 generation = 0; const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - _generate_aes_kek(KS_AES_ECB, keys, keys->temp_key, header_kek_source, generation, option); - _generate_aes_key(KS_AES_ECB, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); + generate_aes_kek(KS_AES_ECB, keys, keys->temp_key, header_kek_source, generation, option); + generate_aes_key(KS_AES_ECB, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); } } -static void _derive_rsa_kek(u32 ks, key_derivation_ctx_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { +static void _derive_rsa_kek(u32 ks, key_storage_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { void *access_key = keys->temp_key; - _generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); - _get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); + generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); + get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); } -static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { +static void _derive_misc_keys(key_storage_t *keys, bool is_dev) { if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { void *access_key = keys->temp_key; const u32 generation = 0; const u32 option = IS_DEVICE_UNIQUE; - _generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); - _load_aes_key(KS_AES_ECB, keys->save_mac_key, access_key, save_mac_key_source); + generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); + load_aes_key(KS_AES_ECB, keys->save_mac_key, access_key, save_mac_key_source); } if (_key_exists(keys->master_key[0])) { @@ -251,18 +229,18 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) { } } -static void _derive_per_generation_keys(key_derivation_ctx_t *keys) { +static void _derive_per_generation_keys(key_storage_t *keys) { for (u32 generation = 0; generation < ARRAY_SIZE(keys->master_key); generation++) { if (!_key_exists(keys->master_key[generation])) continue; for (u32 source_type = 0; source_type < ARRAY_SIZE(key_area_key_sources); source_type++) { void *access_key = keys->temp_key; const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - _generate_aes_kek(KS_AES_ECB, keys, access_key, key_area_key_sources[source_type], generation + 1, option); - _load_aes_key(KS_AES_ECB, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); + generate_aes_kek(KS_AES_ECB, keys, access_key, key_area_key_sources[source_type], generation + 1, option); + load_aes_key(KS_AES_ECB, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); } - _load_aes_key(KS_AES_ECB, keys->package2_key[generation], keys->master_key[generation], package2_key_source); - _load_aes_key(KS_AES_ECB, keys->titlekek[generation], keys->master_key[generation], titlekek_source); + load_aes_key(KS_AES_ECB, keys->package2_key[generation], keys->master_key[generation], package2_key_source); + load_aes_key(KS_AES_ECB, keys->titlekek[generation], keys->master_key[generation], titlekek_source); } } @@ -402,7 +380,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return true; } -static bool _derive_sd_seed(key_derivation_ctx_t *keys) { +static bool _derive_sd_seed(key_storage_t *keys) { FIL fp; u32 read_bytes = 0; char *private_path = malloc(200); @@ -421,7 +399,7 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { return false; } // Get sd seed verification vector - if (f_read(&fp, keys->temp_key, AES_128_KEY_SIZE, &read_bytes) || read_bytes != AES_128_KEY_SIZE) { + if (f_read(&fp, keys->temp_key, SE_KEY_128_SIZE, &read_bytes) || read_bytes != SE_KEY_128_SIZE) { EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); return false; @@ -451,54 +429,8 @@ static bool _derive_sd_seed(key_derivation_ctx_t *keys) { return true; } -static bool _read_cal0(void *read_buffer) { - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)read_buffer; - - // Check if CAL0 was already read into this buffer - if (cal0->magic == MAGIC_CAL0) { - return true; - } - - if (!emummc_storage_read(NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE, NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE, read_buffer)) { - EPRINTF("Unable to read PRODINFO."); - return false; - } - - se_aes_xts_crypt(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, DECRYPT, 0, read_buffer, read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE); - - if (cal0->magic != MAGIC_CAL0) { - EPRINTF("Invalid CAL0 magic. Check BIS key 0."); - return false; - } - - return true; -} - -static bool _cal0_read_ssl_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { - const u32 ext_key_size = sizeof(cal0->ext_ssl_key_iv) + sizeof(cal0->ext_ssl_key); - const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ssl_key_ver) + sizeof(cal0->crc16_pad39); - const u32 key_size = sizeof(cal0->ssl_key_iv) + sizeof(cal0->ssl_key); - const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad18); - - if (cal0->ext_ssl_key_crc == crc16_calc(cal0->ext_ssl_key_iv, ext_key_crc_size)) { - *out_key = cal0->ext_ssl_key; - *out_key_size = ext_key_size; - *out_iv = cal0->ext_ssl_key_iv; - // Settings sysmodule manually zeroes this out below cal version 9 - *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ssl_key_ver; - } else if (cal0->ssl_key_crc == crc16_calc(cal0->ssl_key_iv, key_crc_size)) { - *out_key = cal0->ssl_key; - *out_key_size = key_size; - *out_iv = cal0->ssl_key_iv; - *out_generation = 0; - } else { - return false; - } - return true; -} - -static bool _decrypt_ssl_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer) { - if (!_read_cal0(titlekey_buffer->read_buffer)) { +static bool _decrypt_ssl_rsa_key(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer) { + if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, titlekey_buffer->read_buffer)) { return false; } @@ -507,18 +439,17 @@ static bool _decrypt_ssl_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t * const void *encrypted_key = NULL; const void *iv = NULL; u32 key_size = 0; - void *keypair_ctr_key = NULL; + void *ctr_key = NULL; bool enforce_unique = true; - if (!_cal0_read_ssl_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { - EPRINTF("Crc16 error reading device key."); + if (!cal0_get_ssl_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { return false; } if (key_size == SSL_RSA_KEY_SIZE) { bool all_zero = true; const u8 *key8 = (const u8 *)encrypted_key; - for (u32 i = RSA_2048_KEY_SIZE; i < SSL_RSA_KEY_SIZE; i++) { + for (u32 i = SE_RSA2048_DIGEST_SIZE; i < SSL_RSA_KEY_SIZE; i++) { if (key8[i] != 0) { all_zero = false; break; @@ -526,29 +457,29 @@ static bool _decrypt_ssl_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t * } if (all_zero) { // Keys of this form are not encrypted - memcpy(keys->ssl_rsa_key, encrypted_key, RSA_2048_KEY_SIZE); + memcpy(keys->ssl_rsa_key, encrypted_key, SE_RSA2048_DIGEST_SIZE); return true; } const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; - keypair_ctr_key = keys->ssl_rsa_kek_legacy; - _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); + ctr_key = keys->ssl_rsa_kek_legacy; + _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); enforce_unique = false; } else if (generation) { const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; - keypair_ctr_key = keys->ssl_rsa_kek_personalized; - _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); + ctr_key = keys->ssl_rsa_kek_personalized; + _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); } else { - keypair_ctr_key = keys->ssl_rsa_kek; + ctr_key = keys->ssl_rsa_kek; } u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; - se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, encrypted_key, ctr_size, iv); if (enforce_unique) { - u32 calc_mac[AES_128_KEY_SIZE / 4] = {0}; - _calc_gmac(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, keypair_ctr_key, iv); + u32 calc_mac[SE_KEY_128_SIZE / 4] = {0}; + calc_gmac(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, ctr_key, iv); const u8 *key8 = (const u8 *)encrypted_key; if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { @@ -561,41 +492,8 @@ static bool _decrypt_ssl_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t * return true; } -static bool _cal0_read_eticket_rsa_key(const nx_emmc_cal0_t *cal0, const void **out_key, u32 *out_key_size, const void **out_iv, u32 *out_generation) { - const u32 ext_key_size = sizeof(cal0->ext_ecc_rsa2048_eticket_key_iv) + sizeof(cal0->ext_ecc_rsa2048_eticket_key); - const u32 ext_key_crc_size = ext_key_size + sizeof(cal0->ext_ecc_rsa2048_eticket_key_ver) + sizeof(cal0->crc16_pad38); - const u32 key_size = sizeof(cal0->rsa2048_eticket_key_iv) + sizeof(cal0->rsa2048_eticket_key); - const u32 key_crc_size = key_size + sizeof(cal0->crc16_pad21); - - if (cal0->ext_ecc_rsa2048_eticket_key_crc == crc16_calc(cal0->ext_ecc_rsa2048_eticket_key_iv, ext_key_crc_size)) { - *out_key = cal0->ext_ecc_rsa2048_eticket_key; - *out_key_size = ext_key_size; - *out_iv = cal0->ext_ecc_rsa2048_eticket_key_iv; - // Settings sysmodule manually zeroes this out below cal version 9 - *out_generation = cal0->version <= 8 ? 0 : cal0->ext_ecc_rsa2048_eticket_key_ver; - } else if (cal0->rsa2048_eticket_key_crc == crc16_calc(cal0->rsa2048_eticket_key_iv, key_crc_size)) { - *out_key = cal0->rsa2048_eticket_key; - *out_key_size = key_size; - *out_iv = cal0->rsa2048_eticket_key_iv; - *out_generation = 0; - } else { - return false; - } - return true; -} - -static bool _test_eticket_rsa_keypair(const rsa_keypair_t *keypair) { - // Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent - // and test the keypair since we have the modulus - if ((_read_be_u32(keypair->public_exponent, 0) != RSA_PUBLIC_EXPONENT) || - (!_test_rsa_keypair(keypair->public_exponent, keypair->private_exponent, keypair->modulus))) { - return false; - } - return true; -} - -static bool _decrypt_eticket_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { - if (!_read_cal0(titlekey_buffer->read_buffer)) { +static bool _decrypt_eticket_rsa_key(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { + if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, titlekey_buffer->read_buffer)) { return false; } @@ -604,24 +502,23 @@ static bool _decrypt_eticket_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer const void *encrypted_key = NULL; const void *iv = NULL; u32 key_size = 0; - void *keypair_ctr_key = NULL; + void *ctr_key = NULL; - if (!_cal0_read_eticket_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { - EPRINTF("Crc16 error reading device key."); + if (!cal0_get_eticket_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { return false; } // Handle legacy case if (key_size == ETICKET_RSA_KEYPAIR_SIZE) { const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; - keypair_ctr_key = keys->temp_key; - _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kekek_source, eticket_rsa_kek_source_legacy, generation, option); + ctr_key = keys->temp_key; + _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, eticket_rsa_kekek_source, eticket_rsa_kek_source_legacy, generation, option); - se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); - if (_test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { - memcpy(keys->eticket_rsa_kek, keypair_ctr_key, sizeof(keys->eticket_rsa_kek)); + if (test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + memcpy(keys->eticket_rsa_kek, ctr_key, sizeof(keys->eticket_rsa_kek)); return true; } // Fall through and try usual method if not applicable @@ -629,17 +526,17 @@ static bool _decrypt_eticket_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer if (generation) { const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; - keypair_ctr_key = keys->eticket_rsa_kek_personalized; + ctr_key = keys->eticket_rsa_kek_personalized; const void *kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; - _derive_rsa_kek(KS_AES_ECB, keys, keypair_ctr_key, eticket_rsa_kekek_source, kek_source, generation, option); + _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, eticket_rsa_kekek_source, kek_source, generation, option); } else { - keypair_ctr_key = keys->eticket_rsa_kek; + ctr_key = keys->eticket_rsa_kek; } - se_aes_key_set(KS_AES_CTR, keypair_ctr_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); - if (!_test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + if (!test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { EPRINTF("Invalid eticket keypair."); memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); return false; @@ -648,7 +545,7 @@ static bool _decrypt_eticket_rsa_key(key_derivation_ctx_t *keys, titlekey_buffer return true; } -static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { +static bool _derive_titlekeys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { if (!_key_exists(keys->eticket_rsa_kek)) { return false; } @@ -668,17 +565,17 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return true; } -static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { +static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { // Set BIS keys. // PRODINFO/PRODINFOF - se_aes_key_set(KS_BIS_00_CRYPT, keys->bis_key[0] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_00_TWEAK, keys->bis_key[0] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_00_CRYPT, keys->bis_key[0] + 0x00, SE_KEY_128_SIZE); + se_aes_key_set(KS_BIS_00_TWEAK, keys->bis_key[0] + 0x10, SE_KEY_128_SIZE); // SAFE - se_aes_key_set(KS_BIS_01_CRYPT, keys->bis_key[1] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_01_TWEAK, keys->bis_key[1] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_01_CRYPT, keys->bis_key[1] + 0x00, SE_KEY_128_SIZE); + se_aes_key_set(KS_BIS_01_TWEAK, keys->bis_key[1] + 0x10, SE_KEY_128_SIZE); // SYSTEM/USER - se_aes_key_set(KS_BIS_02_CRYPT, keys->bis_key[2] + 0x00, AES_128_KEY_SIZE); - se_aes_key_set(KS_BIS_02_TWEAK, keys->bis_key[2] + 0x10, AES_128_KEY_SIZE); + se_aes_key_set(KS_BIS_02_CRYPT, keys->bis_key[2] + 0x00, SE_KEY_128_SIZE); + se_aes_key_set(KS_BIS_02_TWEAK, keys->bis_key[2] + 0x10, SE_KEY_128_SIZE); if (!emummc_storage_set_mmc_partition(EMMC_GPP)) { EPRINTF("Unable to set partition."); @@ -745,8 +642,8 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { color_idx = 0; u32 pos = 0; - u32 zeros[AES_128_KEY_SIZE / 4] = {0}; - u8 *data = malloc(4 * AES_128_KEY_SIZE); + u32 zeros[SE_KEY_128_SIZE / 4] = {0}; + u8 *data = malloc(4 * SE_KEY_128_SIZE); char *text_buffer = calloc(1, 0x100 * count); for (u32 ks = start; ks < start + count; ks++) { @@ -760,26 +657,26 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { } // Encrypt zeros with complete key - se_aes_crypt_block_ecb(ks, ENCRYPT, &data[3 * AES_128_KEY_SIZE], zeros); + se_aes_crypt_block_ecb(ks, ENCRYPT, &data[3 * SE_KEY_128_SIZE], zeros); // We only need to overwrite 3 of the dwords of the key for (u32 i = 0; i < 3; i++) { // Overwrite ith dword of key with zeros se_aes_key_partial_set(ks, i, 0); // Encrypt zeros with more of the key zeroed out - se_aes_crypt_block_ecb(ks, ENCRYPT, &data[(2 - i) * AES_128_KEY_SIZE], zeros); + se_aes_crypt_block_ecb(ks, ENCRYPT, &data[(2 - i) * SE_KEY_128_SIZE], zeros); } // Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot - if (memcmp(&data[0], &data[SE_KEY_128_SIZE], AES_128_KEY_SIZE) == 0) { + if (memcmp(&data[0], &data[SE_KEY_128_SIZE], SE_KEY_128_SIZE) == 0) { EPRINTFARGS("Failed to overwrite keyslot %d.", ks); continue; } pos += s_printf(&text_buffer[pos], "%d\n", ks); for (u32 i = 0; i < 4; i++) { - for (u32 j = 0; j < AES_128_KEY_SIZE; j++) - pos += s_printf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]); + for (u32 j = 0; j < SE_KEY_128_SIZE; j++) + pos += s_printf(&text_buffer[pos], "%02x", data[i * SE_KEY_128_SIZE + j]); pos += s_printf(&text_buffer[pos], " "); } pos += s_printf(&text_buffer[pos], "\n"); @@ -823,7 +720,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { return 0; } -static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { +static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { char *text_buffer = NULL; if (!sd_mount()) { EPRINTF("Unable to mount SD."); @@ -896,7 +793,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(ssl_rsa_kek_source); } SAVE_KEY(ssl_rsa_kekek_source); - _save_key("ssl_rsa_key", keys->ssl_rsa_key, RSA_2048_KEY_SIZE, text_buffer); + _save_key("ssl_rsa_key", keys->ssl_rsa_key, SE_RSA2048_DIGEST_SIZE, text_buffer); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); SAVE_KEY_VAR(tsec_key, keys->tsec_key); @@ -904,7 +801,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl const u32 root_key_ver = 2; char root_key_name[21] = "tsec_root_key_00"; s_printf(root_key_name + 14, "%02x", root_key_ver); - _save_key(root_key_name, keys->tsec_root_key, AES_128_KEY_SIZE, text_buffer); + _save_key(root_key_name, keys->tsec_root_key, SE_KEY_128_SIZE, text_buffer); gfx_printf("\n%k Found %d %s keys.\n\n", colors[(color_idx++) % 6], _key_count, is_dev ? "dev" : "prod"); gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX); @@ -929,10 +826,10 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl titlekey_text_buffer_t *titlekey_text = (titlekey_text_buffer_t *)text_buffer; for (u32 i = 0; i < _titlekey_count; i++) { - for (u32 j = 0; j < AES_128_KEY_SIZE; j++) + for (u32 j = 0; j < SE_KEY_128_SIZE; j++) s_printf(&titlekey_text[i].rights_id[j * 2], "%02x", titlekey_buffer->rights_ids[i][j]); s_printf(titlekey_text[i].equals, " = "); - for (u32 j = 0; j < AES_128_KEY_SIZE; j++) + for (u32 j = 0; j < SE_KEY_128_SIZE; j++) s_printf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]); s_printf(titlekey_text[i].newline, "\n"); } @@ -948,16 +845,16 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl } static bool _check_keyslot_access() { - u8 test_data[AES_128_KEY_SIZE] = {0}; - const u8 test_ciphertext[AES_128_KEY_SIZE] = {0}; + u8 test_data[SE_KEY_128_SIZE] = {0}; + const u8 test_ciphertext[SE_KEY_128_SIZE] = {0}; se_aes_key_set(KS_AES_ECB, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, test_data, test_ciphertext); return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; } -static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_ctx_t *dev_keys, bool is_dev) { - key_derivation_ctx_t *keys = is_dev ? dev_keys : prod_keys; +static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_keys, bool is_dev) { + key_storage_t *keys = is_dev ? dev_keys : prod_keys; if (h_cfg.t210b01) { _derive_master_key_mariko(keys, is_dev); @@ -970,10 +867,10 @@ static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_ } u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); - se_get_aes_keys(aes_keys + SZ_2K, aes_keys, AES_128_KEY_SIZE); - memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(keys->tsec_key, aes_keys + KS_TSEC * AES_128_KEY_SIZE, AES_128_KEY_SIZE); - memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); + memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); free(aes_keys); _derive_master_keys_from_latest_key(prod_keys, false); @@ -1009,8 +906,8 @@ static void _derive_keys() { bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; - key_derivation_ctx_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; - key_derivation_ctx_t *keys = is_dev ? &dev_keys : &prod_keys; + key_storage_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; + key_storage_t *keys = is_dev ? &dev_keys : &prod_keys; _derive_master_keys(&prod_keys, &dev_keys, is_dev); @@ -1065,8 +962,8 @@ void derive_amiibo_keys() { bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV; - key_derivation_ctx_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; - key_derivation_ctx_t *keys = is_dev ? &dev_keys : &prod_keys; + key_storage_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; + key_storage_t *keys = is_dev ? &dev_keys : &prod_keys; const u8 *encrypted_keys = is_dev ? encrypted_nfc_keys_dev : encrypted_nfc_keys; _derive_master_keys(&prod_keys, &dev_keys, is_dev); @@ -1088,18 +985,18 @@ void derive_amiibo_keys() { return; } - _decrypt_aes_key(KS_AES_ECB, keys, keys->temp_key, nfc_key_source, 0, 0); + decrypt_aes_key(KS_AES_ECB, keys, keys->temp_key, nfc_key_source, 0, 0); nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; - static const u8 nfc_iv[AES_128_KEY_SIZE] = { + static const u8 nfc_iv[SE_KEY_128_SIZE] = { 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; - se_aes_key_set(KS_AES_CTR, keys->temp_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, keys->temp_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); minerva_periodic_training(); u8 xor_pad[0x20] __attribute__((aligned(4))) = {0}; - se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, AES_128_KEY_SIZE); + se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); minerva_periodic_training(); @@ -1204,111 +1101,3 @@ static void _save_key_family(const char *name, const void *data, u32 start_key, } free(temp_name); } - -// Equivalent to spl::GenerateAesKek -static void _generate_aes_kek(u32 ks, key_derivation_ctx_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option) { - bool device_unique = GET_IS_DEVICE_UNIQUE(option); - u32 seal_key_index = GET_SEAL_KEY_INDEX(option); - - if (generation) - generation--; - - u8 static_source[AES_128_KEY_SIZE] __attribute__((aligned(4))); - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) - static_source[i] = aes_kek_generation_source[i] ^ seal_key_masks[seal_key_index][i]; - - if (device_unique) { - _get_device_key(ks, keys, keys->temp_key, generation); - } else { - memcpy(keys->temp_key, keys->master_key[generation], sizeof(keys->temp_key)); - } - se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, static_source); - se_aes_crypt_block_ecb(ks, DECRYPT, out_kek, kek_source); -} - -// Based on spl::LoadAesKey but instead of prepping keyslot, returns calculated key -static void _load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { - se_aes_key_set(ks, access_key, AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(ks, DECRYPT, out_key, key_source); -} - -// Equivalent to spl::GenerateAesKey -static void _generate_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source) { - void *aes_key = keys->temp_key; - _load_aes_key(ks, aes_key, access_key, aes_key_generation_source); - se_aes_key_set(ks, aes_key, AES_128_KEY_SIZE); - se_aes_crypt_ecb(ks, DECRYPT, out_key, key_size, key_source, key_size); -} - -// Equivalent to smc::PrepareDeviceUniqueDataKey but with no sealing -static void _get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, const void *key_source) { - _load_aes_key(ks, out_key, access_key, key_source); -} - -// Equivalent to spl::DecryptAesKey. -static void _decrypt_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation, u32 option) { - void *access_key = keys->temp_key; - _generate_aes_kek(ks, keys, access_key, aes_key_decryption_source, generation, option); - _generate_aes_key(ks, keys, out_key, AES_128_KEY_SIZE, access_key, key_source); -} - -// Equivalent to smc::GetSecureData -static void _get_secure_data(key_derivation_ctx_t *keys, void *out_data) { - se_aes_key_set(KS_AES_CTR, keys->device_key, AES_128_KEY_SIZE); - u8 *d = (u8 *)out_data; - se_aes_crypt_ctr(KS_AES_CTR, d + AES_128_KEY_SIZE * 0, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); - se_aes_crypt_ctr(KS_AES_CTR, d + AES_128_KEY_SIZE * 1, AES_128_KEY_SIZE, secure_data_source, AES_128_KEY_SIZE, secure_data_counters[0]); - - // Apply tweak - for (u32 i = 0; i < AES_128_KEY_SIZE; i++) { - d[AES_128_KEY_SIZE + i] ^= secure_data_tweaks[0][i]; - } -} - -// Equivalent to spl::GenerateSpecificAesKey -static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void *out_key, const void *key_source, u32 generation) { - if (fuse_read_bootrom_rev() >= 0x7F) { - _get_device_key(ks, keys, keys->temp_key, generation == 0 ? 0 : generation - 1); - se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); - se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); - } else { - _get_secure_data(keys, out_key); - } -} - -static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 generation) { - if (generation == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) { - memcpy(out_device_key, keys->device_key, AES_128_KEY_SIZE); - return; - } - - if (generation >= KB_FIRMWARE_VERSION_400) { - generation -= KB_FIRMWARE_VERSION_400; - } else { - generation = 0; - } - u32 temp_key_source[AES_128_KEY_SIZE / 4] = {0}; - _load_aes_key(ks, temp_key_source, keys->device_key_4x, device_master_key_source_sources[generation]); - const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[generation] : device_master_kek_sources_dev[generation]; - se_aes_key_set(ks, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_unwrap_key(ks, ks, kek_source); - se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key_source); -} - -static bool _test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus) { - u32 plaintext[RSA_2048_KEY_SIZE / 4] = {0}, - ciphertext[RSA_2048_KEY_SIZE / 4] = {0}, - work[RSA_2048_KEY_SIZE / 4] = {0}; - - plaintext[63] = 0xCAFEBABE; - - se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, private_exponent, RSA_2048_KEY_SIZE); - se_rsa_exp_mod(0, ciphertext, RSA_2048_KEY_SIZE, plaintext, RSA_2048_KEY_SIZE); - - se_rsa_key_set(0, modulus, RSA_2048_KEY_SIZE, public_exponent, 4); - se_rsa_exp_mod(0, work, RSA_2048_KEY_SIZE, ciphertext, RSA_2048_KEY_SIZE); - - return memcmp(plaintext, work, RSA_2048_KEY_SIZE) == 0; -} diff --git a/source/keys/keys.h b/source/keys/keys.h index bb1b5af..ca84f85 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -17,45 +17,19 @@ #ifndef _KEYS_H_ #define _KEYS_H_ -#include +#include "crypto.h" #include "../hos/hos.h" - -#define AES_128_KEY_SIZE 16 -#define RSA_2048_KEY_SIZE 256 - -#define RSA_PUBLIC_EXPONENT 65537 - -// Lockpick_RCM keyslots -#define KS_BIS_00_CRYPT 0 -#define KS_BIS_00_TWEAK 1 -#define KS_BIS_01_CRYPT 2 -#define KS_BIS_01_TWEAK 3 -#define KS_BIS_02_CRYPT 4 -#define KS_BIS_02_TWEAK 5 -#define KS_AES_CTR 6 -#define KS_AES_ECB 8 -#define KS_AES_CMAC 10 - -// Mariko keyslots -#define KS_MARIKO_KEK 12 -#define KS_MARIKO_BEK 13 - -// Other Switch keyslots -#define KS_TSEC 12 -#define KS_SECURE_BOOT 14 - -// Atmosphere keygen keyslots -#define KS_TSEC_ROOT_DEV 11 -#define KS_TSEC_ROOT 13 +#include +#include // only tickets of type Rsa2048Sha256 are expected typedef struct { u32 signature_type; // always 0x10004 - u8 signature[RSA_2048_KEY_SIZE]; + u8 signature[SE_RSA2048_DIGEST_SIZE]; u8 sig_padding[0x3C]; char issuer[0x40]; - u8 titlekey_block[RSA_2048_KEY_SIZE]; + u8 titlekey_block[SE_RSA2048_DIGEST_SIZE]; u8 format_version; u8 titlekey_type; u16 ticket_version; @@ -88,26 +62,6 @@ typedef struct { u8 titlekeys[SZ_256K / 0x10][0x10]; } titlekey_buffer_t; -typedef struct { - u8 private_exponent[RSA_2048_KEY_SIZE]; - u8 modulus[RSA_2048_KEY_SIZE]; - u8 public_exponent[4]; - u8 reserved[0xC]; -} rsa_keypair_t; - -typedef struct { - u8 master_kek[AES_128_KEY_SIZE]; - u8 data[0x70]; - u8 package1_key[AES_128_KEY_SIZE]; -} keyblob_t; - -typedef struct { - u8 cmac[0x10]; - u8 iv[0x10]; - keyblob_t key_data; - u8 unused[0x150]; -} encrypted_keyblob_t; - typedef struct { char phrase[0xE]; u8 seed[0xE]; @@ -129,61 +83,6 @@ typedef struct { u8 xor_pad[0x20]; } nfc_save_key_t; -typedef enum { - SEAL_KEY_LOAD_AES_KEY = 0, - SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA = 1, - SEAL_KEY_IMPORT_LOTUS_KEY = 2, - SEAL_KEY_IMPORT_ES_DEVICE_KEY = 3, - SEAL_KEY_REENCRYPT_DEVICE_UNIQUE_DATA = 4, - SEAL_KEY_IMPORT_SSL_KEY = 5, - SEAL_KEY_IMPORT_ES_CLIENT_CERT_KEY = 6, -} seal_key_t; - -typedef enum { - NOT_DEVICE_UNIQUE = 0, - IS_DEVICE_UNIQUE = 1, -} device_unique_t; - -#define SET_SEAL_KEY_INDEX(x) (((x) & 7) << 5) -#define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) -#define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) - -#define SSL_RSA_KEY_SIZE (RSA_2048_KEY_SIZE + AES_128_KEY_SIZE) -#define ETICKET_RSA_KEYPAIR_SIZE (RSA_2048_KEY_SIZE * 2 + AES_128_KEY_SIZE * 2) - -typedef struct { - u8 temp_key[AES_128_KEY_SIZE], - bis_key[4][AES_128_KEY_SIZE * 2], - device_key[AES_128_KEY_SIZE], - device_key_4x[AES_128_KEY_SIZE], - sd_seed[AES_128_KEY_SIZE], - // FS-related keys - header_key[AES_128_KEY_SIZE * 2], - save_mac_key[AES_128_KEY_SIZE], - // other sysmodule keys - eticket_rsa_kek[AES_128_KEY_SIZE], - eticket_rsa_kek_personalized[AES_128_KEY_SIZE], - ssl_rsa_kek[AES_128_KEY_SIZE], - ssl_rsa_kek_legacy[AES_128_KEY_SIZE], - ssl_rsa_kek_personalized[AES_128_KEY_SIZE], - ssl_rsa_key[RSA_2048_KEY_SIZE + 0x20], - // keyblob-derived families - keyblob_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], - keyblob_mac_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], - package1_key[KB_FIRMWARE_VERSION_600 + 1][AES_128_KEY_SIZE], - // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - master_kek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - tsec_key[AES_128_KEY_SIZE], - tsec_root_key[AES_128_KEY_SIZE]; - u32 sbk[4]; - keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; - rsa_keypair_t eticket_rsa_keypair; -} key_derivation_ctx_t; - typedef struct { char rights_id[0x20]; char equals[3]; From c7d90ec8caf22a901c2b9bb816f6c2e346aa42a6 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 2 Nov 2022 18:36:39 -0700 Subject: [PATCH 158/166] Further improve readability --- bdk/sec/se.c | 70 -------------- bdk/sec/se.h | 1 - bdk/utils/util.c | 14 --- bdk/utils/util.h | 3 - source/keys/crypto.c | 83 +++++++++++++++- source/keys/crypto.h | 7 +- source/keys/keys.c | 222 +++++++++++++++++++++---------------------- source/keys/keys.h | 2 +- 8 files changed, 195 insertions(+), 207 deletions(-) diff --git a/bdk/sec/se.c b/bdk/sec/se.c index 02f6f90..5c2a391 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -718,76 +718,6 @@ out:; return res; } -// _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) -{ - u8 cur_hash[0x20] __attribute__((aligned(4))); - u8 hash_buf[0xe4] __attribute__((aligned(4))); - - u32 hash_buf_size = seed_size + 4; - memcpy(hash_buf, seed, seed_size); - u32 round_num = 0; - - u8 *p_out = (u8 *)masked; - - while (masked_size) { - u32 cur_size = MIN(masked_size, 0x20); - - for (u32 i = 0; i < 4; i++) - hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; - round_num++; - - se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size); - - for (unsigned int i = 0; i < cur_size; i++) { - *p_out ^= cur_hash[i]; - p_out++; - } - - masked_size -= cur_size; - } -} - -u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size) -{ - if (dst_size <= 0 || buf_size < 0x43 || label_digest_size != 0x20) - return 0; - - bool is_valid = buf[0] == 0; - - u32 db_len = buf_size - 0x21; - u8 *seed = buf + 1; - u8 *db = seed + 0x20; - _mgf1_xor(seed, 0x20, db, db_len); - _mgf1_xor(db, db_len, seed, 0x20); - - is_valid &= memcmp(label_digest, db, 0x20) ? 0 : 1; - - db += 0x20; - db_len -= 0x20; - - int msg_ofs = 0; - int looking_for_one = 1; - int invalid_db_padding = 0; - int is_zero; - int is_one; - for (int i = 0; i < db_len; ) - { - is_zero = (db[i] == 0); - is_one = (db[i] == 1); - msg_ofs += (looking_for_one & is_one) * (++i); - looking_for_one &= ~is_one; - invalid_db_padding |= (looking_for_one & ~is_zero); - } - - is_valid &= (invalid_db_padding == 0); - - const u32 msg_size = MIN(dst_size, is_valid * (db_len - msg_ofs)); - memcpy(dst, db + msg_ofs, msg_size); - - return msg_size; -} - void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) { u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40); diff --git a/bdk/sec/se.h b/bdk/sec/se.h index 2a2f8cd..1bb435d 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -49,6 +49,5 @@ int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); int se_calc_sha256_finalize(void *hash, u32 *msg_left); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); -u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); #endif diff --git a/bdk/utils/util.c b/bdk/utils/util.c index e05c2bc..bf30929 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -230,17 +230,3 @@ void power_set_state_ex(void *param) power_state_t *state = (power_state_t *)param; power_set_state(*state); } - -u32 read_le_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 0) ) | - (*(u8*)(buffer + offset + 1) << 0x08) | - (*(u8*)(buffer + offset + 2) << 0x10) | - (*(u8*)(buffer + offset + 3) << 0x18); -} - -u32 read_be_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 3) ) | - (*(u8*)(buffer + offset + 2) << 0x08) | - (*(u8*)(buffer + offset + 1) << 0x10) | - (*(u8*)(buffer + offset + 0) << 0x18); -} diff --git a/bdk/utils/util.h b/bdk/utils/util.h index df929bc..d27d52d 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -96,7 +96,4 @@ void panic(u32 val); void power_set_state(power_state_t state); void power_set_state_ex(void *param); -u32 read_le_u32(const void *buffer, u32 offset); -u32 read_be_u32(const void *buffer, u32 offset); - #endif diff --git a/source/keys/crypto.c b/source/keys/crypto.c index cd5afd0..42e10bb 100644 --- a/source/keys/crypto.c +++ b/source/keys/crypto.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 shchmue + * Copyright (c) 2018 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -27,6 +28,15 @@ extern hekate_config h_cfg; +bool check_keyslot_access() { + u8 test_data[SE_KEY_128_SIZE] = {0}; + const u8 test_ciphertext[SE_KEY_128_SIZE] = {0}; + se_aes_key_set(KS_AES_ECB, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); + se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, test_data, test_ciphertext); + + return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; +} + bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus) { u32 plaintext[SE_RSA2048_DIGEST_SIZE / 4] = {0}, ciphertext[SE_RSA2048_DIGEST_SIZE / 4] = {0}, @@ -46,13 +56,82 @@ bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair) { // Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent // and test the keypair since we have the modulus - if ((read_be_u32(keypair->public_exponent, 0) != RSA_PUBLIC_EXPONENT) || - (!test_rsa_keypair(keypair->public_exponent, keypair->private_exponent, keypair->modulus))) { + if ((byte_swap_32(keypair->public_exponent) != RSA_PUBLIC_EXPONENT) || + (!test_rsa_keypair(&keypair->public_exponent, keypair->private_exponent, keypair->modulus)) + ) { return false; } return true; } +// _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) +{ + u8 cur_hash[0x20] __attribute__((aligned(4))); + u8 hash_buf[0xe4] __attribute__((aligned(4))); + + u32 hash_buf_size = seed_size + 4; + memcpy(hash_buf, seed, seed_size); + u32 round_num = 0; + + u8 *p_out = (u8 *)masked; + + while (masked_size) { + u32 cur_size = MIN(masked_size, 0x20); + + for (u32 i = 0; i < 4; i++) + hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; + round_num++; + + se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size); + + for (unsigned int i = 0; i < cur_size; i++) { + *p_out ^= cur_hash[i]; + p_out++; + } + + masked_size -= cur_size; + } +} + +u32 rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size) { + if (dst_size <= 0 || buf_size < 0x43 || label_digest_size != 0x20) + return 0; + + bool is_valid = buf[0] == 0; + + u32 db_len = buf_size - 0x21; + u8 *seed = buf + 1; + u8 *db = seed + 0x20; + _mgf1_xor(seed, 0x20, db, db_len); + _mgf1_xor(db, db_len, seed, 0x20); + + is_valid &= memcmp(label_digest, db, 0x20) ? 0 : 1; + + db += 0x20; + db_len -= 0x20; + + int msg_ofs = 0; + int looking_for_one = 1; + int invalid_db_padding = 0; + int is_zero; + int is_one; + for (int i = 0; i < db_len; ) { + is_zero = (db[i] == 0); + is_one = (db[i] == 1); + msg_ofs += (looking_for_one & is_one) * (++i); + looking_for_one &= ~is_one; + invalid_db_padding |= (looking_for_one & ~is_zero); + } + + is_valid &= (invalid_db_padding == 0); + + const u32 msg_size = MIN(dst_size, is_valid * (db_len - msg_ofs)); + memcpy(dst, db + msg_ofs, msg_size); + + return msg_size; +} + // Equivalent to spl::GenerateAesKek void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option) { bool device_unique = GET_IS_DEVICE_UNIQUE(option); diff --git a/source/keys/crypto.h b/source/keys/crypto.h index 4e1d0d7..33389f8 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -127,10 +127,12 @@ static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { #define SSL_RSA_KEY_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE) #define ETICKET_RSA_KEYPAIR_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE * 2 + SE_KEY_128_SIZE) +#define TICKET_SIG_TYPE_RSA2048_SHA256 0x10004 + typedef struct { u8 private_exponent[SE_RSA2048_DIGEST_SIZE]; u8 modulus[SE_RSA2048_DIGEST_SIZE]; - u8 public_exponent[4]; + u32 public_exponent; u8 reserved[0xC]; } rsa_keypair_t; @@ -199,8 +201,11 @@ typedef enum { #define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) #define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) +bool check_keyslot_access(); + bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus); bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair); +u32 rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); // Equivalent to spl::GenerateAesKek void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option); diff --git a/source/keys/keys.c b/source/keys/keys.c index a53061e..f7fc7c3 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -65,6 +65,7 @@ static void _save_key(const char *name, const void *data, u32 len, char *outbuf) static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); static void _derive_master_key_mariko(key_storage_t *keys, bool is_dev) { + minerva_periodic_training(); // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); // Derive all master keys based on Mariko KEK @@ -94,6 +95,7 @@ static int _run_ams_keygen(key_storage_t *keys) { } static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev) { + minerva_periodic_training(); if (!h_cfg.t210b01) { u32 tsec_root_key_slot = is_dev ? 11 : 13; // Derive all master keys based on current root key @@ -103,6 +105,8 @@ static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev } } + minerva_periodic_training(); + // Derive all lower master keys for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { load_aes_key(KS_AES_ECB, keys->master_key[i - 1], keys->master_key[i], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]); @@ -116,6 +120,8 @@ static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev } static void _derive_keyblob_keys(key_storage_t *keys) { + minerva_periodic_training(); + u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); u32 keyblob_mac[SE_KEY_128_SIZE / 4] = {0}; bool have_keyblobs = true; @@ -194,6 +200,7 @@ static void _derive_bis_keys(key_storage_t *keys) { } static void _derive_non_unique_keys(key_storage_t *keys, bool is_dev) { + minerva_periodic_training(); if (_key_exists(keys->master_key[0])) { const u32 generation = 0; const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); @@ -209,6 +216,7 @@ static void _derive_rsa_kek(u32 ks, key_storage_t *keys, void *out_rsa_kek, cons } static void _derive_misc_keys(key_storage_t *keys, bool is_dev) { + minerva_periodic_training(); if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { void *access_key = keys->temp_key; const u32 generation = 0; @@ -231,6 +239,7 @@ static void _derive_misc_keys(key_storage_t *keys, bool is_dev) { static void _derive_per_generation_keys(key_storage_t *keys) { for (u32 generation = 0; generation < ARRAY_SIZE(keys->master_key); generation++) { + minerva_periodic_training(); if (!_key_exists(keys->master_key[generation])) continue; for (u32 source_type = 0; source_type < ARRAY_SIZE(key_area_key_sources); source_type++) { @@ -244,6 +253,45 @@ static void _derive_per_generation_keys(key_storage_t *keys) { } } +// Returns true when terminator is found +static bool _count_ticket_records(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u32 *tkey_count) { + ticket_record_t *curr_ticket_record = (ticket_record_t *)titlekey_buffer->read_buffer; + for (u32 i = 0; i < buf_size; i += sizeof(ticket_record_t), curr_ticket_record++) { + if (curr_ticket_record->rights_id[0] == 0xFF) + return true; + (*tkey_count)++; + } + return false; +} + +static void _decode_tickets(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u32 remaining, u32 total, u32 x, u32 y, u32 *pct, u32 *last_pct, bool is_personalized) { + ticket_t *curr_ticket = (ticket_t *)titlekey_buffer->read_buffer; + for (u32 i = 0; i < MIN(buf_size / sizeof(ticket_t), remaining) * sizeof(ticket_t) && curr_ticket->signature_type != 0; i += sizeof(ticket_t), curr_ticket++) { + minerva_periodic_training(); + *pct = (total - remaining) * 100 / total; + if (*pct > *last_pct && *pct <= 100) { + *last_pct = *pct; + tui_pbar(x, y, *pct, COLOR_GREEN, 0xFF155500); + } + + // This is in case an encrypted volatile ticket is left behind + if (curr_ticket->signature_type != TICKET_SIG_TYPE_RSA2048_SHA256) + continue; + + u8 *curr_titlekey = curr_ticket->titlekey_block; + const u32 block_size = SE_RSA2048_DIGEST_SIZE; + const u32 titlekey_size = sizeof(titlekey_buffer->titlekeys[0]); + if (is_personalized) { + se_rsa_exp_mod(0, curr_titlekey, block_size, curr_titlekey, block_size); + if (rsa_oaep_decode(curr_titlekey, titlekey_size, null_hash, sizeof(null_hash), curr_titlekey, block_size) != titlekey_size) + continue; + } + memcpy(titlekey_buffer->rights_ids[_titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); + memcpy(titlekey_buffer->titlekeys[_titlekey_count], curr_titlekey, titlekey_size); + _titlekey_count++; + } +} + static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { FIL fp; u64 br = buf_size; @@ -251,8 +299,10 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title u32 file_tkey_count = 0; u32 save_x = gfx_con.x, save_y = gfx_con.y; bool is_personalized = rsa_keypair != NULL; - u32 start_titlekey_count = _titlekey_count; + const char ticket_bin_path[32] = "/ticket.bin"; + const char ticket_list_bin_path[32] = "/ticket_list.bin"; char titlekey_save_path[32] = "bis:/save/80000000000000E1"; + save_data_file_ctx_t ticket_file; if (is_personalized) { titlekey_save_path[25] = '2'; @@ -280,10 +330,6 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } - const char ticket_bin_path[32] = "/ticket.bin"; - const char ticket_list_bin_path[32] = "/ticket_list.bin"; - save_data_file_ctx_t ticket_file; - if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket_list.bin in save."); f_close(&fp); @@ -292,22 +338,19 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } - bool terminator_reached = false; - while (offset < ticket_file.size && !terminator_reached) { - if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) - break; - offset += br; + // Read ticket list to get ticket count + while (offset < ticket_file.size) { minerva_periodic_training(); - ticket_record_t *curr_ticket_record = (ticket_record_t *)titlekey_buffer->read_buffer; - for (u32 i = 0; i < buf_size; i += sizeof(ticket_record_t), curr_ticket_record++) { - if (curr_ticket_record->rights_id[0] == 0xFF) { - terminator_reached = true; - break; - } - file_tkey_count++; + if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || + titlekey_buffer->read_buffer[0] == 0 || + br != buf_size || + _count_ticket_records(buf_size, titlekey_buffer, &file_tkey_count) + ) { + break; } + offset += br; } - TPRINTF(" Count keys..."); + TPRINTF(" Count titlekeys..."); if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket.bin in save."); @@ -317,50 +360,17 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title return false; } - if (is_personalized) { + if (is_personalized) se_rsa_key_set(0, rsa_keypair->modulus, sizeof(rsa_keypair->modulus), rsa_keypair->private_exponent, sizeof(rsa_keypair->private_exponent)); - } - - const u32 ticket_sig_type_rsa2048_sha256 = 0x10004; offset = 0; - terminator_reached = false; - u32 pct = 0, last_pct = 0, i = 0; - while (offset < ticket_file.size && !terminator_reached) { + u32 pct = 0, last_pct = 0, remaining = file_tkey_count; + while (offset < ticket_file.size && remaining) { if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) break; offset += br; - ticket_t *curr_ticket = (ticket_t *)titlekey_buffer->read_buffer; - for (u32 j = 0; j < buf_size; j += sizeof(ticket_t), curr_ticket++) { - minerva_periodic_training(); - pct = (_titlekey_count - start_titlekey_count) * 100 / file_tkey_count; - if (pct > last_pct && pct <= 100) { - last_pct = pct; - tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); - } - if (i == file_tkey_count || curr_ticket->signature_type == 0) { - terminator_reached = true; - break; - } - if (curr_ticket->signature_type != ticket_sig_type_rsa2048_sha256) { - i++; - continue; - } - if (is_personalized) { - se_rsa_exp_mod(0, curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block), curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block)); - if (se_rsa_oaep_decode( - curr_ticket->titlekey_block, sizeof(titlekey_buffer->titlekeys[0]), - null_hash, sizeof(null_hash), - curr_ticket->titlekey_block, sizeof(curr_ticket->titlekey_block) - ) != sizeof(titlekey_buffer->titlekeys[0]) - ) - continue; - } - memcpy(titlekey_buffer->rights_ids[_titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); - memcpy(titlekey_buffer->titlekeys[_titlekey_count], curr_ticket->titlekey_block, sizeof(titlekey_buffer->titlekeys[0])); - _titlekey_count++; - i++; - } + _decode_tickets(buf_size, titlekey_buffer, remaining, file_tkey_count, save_x, save_y, &pct, &last_pct, is_personalized); + remaining -= MIN(buf_size / sizeof(ticket_t), remaining); } tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); f_close(&fp); @@ -844,21 +854,11 @@ static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_bu free(text_buffer); } -static bool _check_keyslot_access() { - u8 test_data[SE_KEY_128_SIZE] = {0}; - const u8 test_ciphertext[SE_KEY_128_SIZE] = {0}; - se_aes_key_set(KS_AES_ECB, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE); - se_aes_crypt_block_ecb(KS_AES_ECB, DECRYPT, test_data, test_ciphertext); - - return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0; -} - static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_keys, bool is_dev) { key_storage_t *keys = is_dev ? dev_keys : prod_keys; if (h_cfg.t210b01) { _derive_master_key_mariko(keys, is_dev); - minerva_periodic_training(); _derive_master_keys_from_latest_key(keys, is_dev); } else { int res = _run_ams_keygen(keys); @@ -874,9 +874,7 @@ static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_key free(aes_keys); _derive_master_keys_from_latest_key(prod_keys, false); - minerva_periodic_training(); _derive_master_keys_from_latest_key(dev_keys, true); - minerva_periodic_training(); _derive_keyblob_keys(keys); } } @@ -884,7 +882,7 @@ static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_key static void _derive_keys() { minerva_periodic_training(); - if (!_check_keyslot_access()) { + if (!check_keyslot_access()) { EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip."); return; } @@ -917,19 +915,10 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - minerva_periodic_training(); _derive_misc_keys(keys, is_dev); - - minerva_periodic_training(); _derive_non_unique_keys(&prod_keys, is_dev); - - minerva_periodic_training(); _derive_non_unique_keys(&dev_keys, is_dev); - - minerva_periodic_training(); _derive_per_generation_keys(&prod_keys); - - minerva_periodic_training(); _derive_per_generation_keys(&dev_keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; @@ -957,6 +946,37 @@ static void _derive_keys() { } } + static void _decrypt_amiibo_keys(key_storage_t *keys, const u8 *encrypted_keys, nfc_save_key_t nfc_save_keys[2]) { + u32 kek[SE_KEY_128_SIZE / 4] = {0}; + decrypt_aes_key(KS_AES_ECB, keys, kek, nfc_key_source, 0, 0); + + nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; + static const u8 nfc_iv[SE_KEY_128_SIZE] = { + 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; + se_aes_key_set(KS_AES_CTR, kek, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); + + minerva_periodic_training(); + + u32 xor_pad[0x20 / 4] = {0}; + se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); + + minerva_periodic_training(); + + memcpy(nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key)); + memcpy(nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase)); + nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed); + memcpy(nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed)); + memcpy(nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad)); + + memcpy(nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif)); + memcpy(nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif)); + nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif); + memcpy(nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif)); + memcpy(nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad)); + } + void derive_amiibo_keys() { minerva_change_freq(FREQ_1600); @@ -985,53 +1005,25 @@ void derive_amiibo_keys() { return; } - decrypt_aes_key(KS_AES_ECB, keys, keys->temp_key, nfc_key_source, 0, 0); - - nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; - static const u8 nfc_iv[SE_KEY_128_SIZE] = { - 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; - se_aes_key_set(KS_AES_CTR, keys->temp_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); - - minerva_periodic_training(); - - u8 xor_pad[0x20] __attribute__((aligned(4))) = {0}; - se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); - - minerva_periodic_training(); - nfc_save_key_t __attribute__((aligned(4))) nfc_save_keys[2] = {0}; - memcpy(nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key)); - memcpy(nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase)); - nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed); - memcpy(nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed)); - memcpy(nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad)); - memcpy(nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif)); - memcpy(nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif)); - nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif); - memcpy(nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif)); - memcpy(nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad)); + _decrypt_amiibo_keys(keys, encrypted_keys, nfc_save_keys); minerva_periodic_training(); - u8 hash[0x20] = {0}; + u32 hash[SE_SHA_256_SIZE / 4] = {0}; se_calc_sha256_oneshot(hash, &nfc_save_keys[0], sizeof(nfc_save_keys)); if (memcmp(hash, is_dev ? nfc_blob_hash_dev : nfc_blob_hash, sizeof(hash)) != 0) { EPRINTF("Amiibo hash mismatch. Skipping save."); - minerva_change_freq(FREQ_800); - btn_wait(); - return; - } - - const char *keyfile_path = is_dev ? "sd:/switch/key_dev.bin" : "sd:/switch/key_retail.bin"; - - if (!sd_save_to_file(&nfc_save_keys[0], sizeof(nfc_save_keys), keyfile_path)) { - gfx_printf("%kWrote Amiibo keys to\n %s\n", colors[(color_idx++) % 6], keyfile_path); } else { - EPRINTF("Unable to save Amiibo keys to SD."); + const char *keyfile_path = is_dev ? "sd:/switch/key_dev.bin" : "sd:/switch/key_retail.bin"; + + if (!sd_save_to_file(&nfc_save_keys[0], sizeof(nfc_save_keys), keyfile_path)) { + gfx_printf("%kWrote Amiibo keys to\n %s\n", colors[(color_idx++) % 6], keyfile_path); + } else { + EPRINTF("Unable to save Amiibo keys to SD."); + } } gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx++) % 6]); diff --git a/source/keys/keys.h b/source/keys/keys.h index ca84f85..3f15719 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -25,7 +25,7 @@ // only tickets of type Rsa2048Sha256 are expected typedef struct { - u32 signature_type; // always 0x10004 + u32 signature_type; // always 0x10004 u8 signature[SE_RSA2048_DIGEST_SIZE]; u8 sig_padding[0x3C]; char issuer[0x40]; From dd41e3fee82f69eb3021cc69512aad686aa6209c Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Nov 2022 14:39:02 -0700 Subject: [PATCH 159/166] keys: Split crypto functions by sysmodule --- source/keys/crypto.c | 48 ++++--- source/keys/crypto.h | 20 +-- source/keys/es_crypto.c | 58 +++++++++ source/keys/es_crypto.h | 40 ++++++ source/keys/es_types.h | 30 +++++ source/keys/fs_crypto.c | 69 ++++++++++ source/keys/fs_crypto.h | 74 +++++++++++ source/keys/key_sources.inl | 123 ++---------------- source/keys/keys.c | 243 +++++++++++------------------------- source/keys/keys.h | 21 ---- source/keys/nfc_crypto.c | 54 ++++++++ source/keys/nfc_crypto.h | 75 +++++++++++ source/keys/ssl_crypto.c | 51 ++++++++ source/keys/ssl_crypto.h | 41 ++++++ 14 files changed, 621 insertions(+), 326 deletions(-) create mode 100644 source/keys/es_crypto.c create mode 100644 source/keys/es_crypto.h create mode 100644 source/keys/es_types.h create mode 100644 source/keys/fs_crypto.c create mode 100644 source/keys/fs_crypto.h create mode 100644 source/keys/nfc_crypto.c create mode 100644 source/keys/nfc_crypto.h create mode 100644 source/keys/ssl_crypto.c create mode 100644 source/keys/ssl_crypto.h diff --git a/source/keys/crypto.c b/source/keys/crypto.c index 42e10bb..46a7564 100644 --- a/source/keys/crypto.c +++ b/source/keys/crypto.c @@ -17,10 +17,13 @@ #include "crypto.h" +#include "../../keygen/tsec_keygen.h" + #include "../config.h" #include "../hos/hos.h" #include #include +#include #include #include @@ -28,6 +31,27 @@ extern hekate_config h_cfg; +int key_exists(const void *data) { + return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; +} + +int run_ams_keygen(key_storage_t *keys) { + tsec_ctxt_t tsec_ctxt; + tsec_ctxt.fw = tsec_keygen; + tsec_ctxt.size = sizeof(tsec_keygen); + tsec_ctxt.type = TSEC_FW_TYPE_NEW; + + u32 retries = 0; + while (tsec_query(keys->temp_key, &tsec_ctxt) < 0) { + retries++; + if (retries > 15) { + return -1; + } + } + + return 0; +} + bool check_keyslot_access() { u8 test_data[SE_KEY_128_SIZE] = {0}; const u8 test_ciphertext[SE_KEY_128_SIZE] = {0}; @@ -53,20 +77,8 @@ bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, return memcmp(plaintext, work, SE_RSA2048_DIGEST_SIZE) == 0; } -bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair) { - // Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent - // and test the keypair since we have the modulus - if ((byte_swap_32(keypair->public_exponent) != RSA_PUBLIC_EXPONENT) || - (!test_rsa_keypair(&keypair->public_exponent, keypair->private_exponent, keypair->modulus)) - ) { - return false; - } - return true; -} - // _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) -{ +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { u8 cur_hash[0x20] __attribute__((aligned(4))); u8 hash_buf[0xe4] __attribute__((aligned(4))); @@ -132,6 +144,12 @@ u32 rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label return msg_size; } +void derive_rsa_kek(u32 ks, key_storage_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; + generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); + get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); +} + // Equivalent to spl::GenerateAesKek void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option) { bool device_unique = GET_IS_DEVICE_UNIQUE(option); @@ -162,7 +180,7 @@ void load_aes_key(u32 ks, void *out_key, const void *access_key, const void *key // Equivalent to spl::GenerateAesKey void generate_aes_key(u32 ks, key_storage_t *keys, void *out_key, u32 key_size, const void *access_key, const void *key_source) { - void *aes_key = keys->temp_key; + u32 aes_key[SE_KEY_128_SIZE / 4] = {0}; load_aes_key(ks, aes_key, access_key, aes_key_generation_source); se_aes_key_set(ks, aes_key, SE_KEY_128_SIZE); se_aes_crypt_ecb(ks, DECRYPT, out_key, key_size, key_source, key_size); @@ -175,7 +193,7 @@ void get_device_unique_data_key(u32 ks, void *out_key, const void *access_key, c // Equivalent to spl::DecryptAesKey. void decrypt_aes_key(u32 ks, key_storage_t *keys, void *out_key, const void *key_source, u32 generation, u32 option) { - void *access_key = keys->temp_key; + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; generate_aes_kek(ks, keys, access_key, aes_key_decryption_source, generation, option); generate_aes_key(ks, keys, out_key, SE_KEY_128_SIZE, access_key, key_source); } diff --git a/source/keys/crypto.h b/source/keys/crypto.h index 33389f8..c242485 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -17,10 +17,14 @@ #ifndef _CRYPTO_H_ #define _CRYPTO_H_ +#include "es_types.h" + #include "../hos/hos.h" #include #include +#include + static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; @@ -129,13 +133,6 @@ static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { #define TICKET_SIG_TYPE_RSA2048_SHA256 0x10004 -typedef struct { - u8 private_exponent[SE_RSA2048_DIGEST_SIZE]; - u8 modulus[SE_RSA2048_DIGEST_SIZE]; - u32 public_exponent; - u8 reserved[0xC]; -} rsa_keypair_t; - typedef struct { u8 master_kek[SE_KEY_128_SIZE]; u8 data[0x70]; @@ -179,7 +176,7 @@ typedef struct { tsec_root_key[SE_KEY_128_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; - rsa_keypair_t eticket_rsa_keypair; + eticket_rsa_keypair_t eticket_rsa_keypair; } key_storage_t; typedef enum { @@ -201,12 +198,17 @@ typedef enum { #define GET_SEAL_KEY_INDEX(x) (((x) >> 5) & 7) #define GET_IS_DEVICE_UNIQUE(x) ((x) & 1) +int key_exists(const void *data); + +int run_ams_keygen(key_storage_t *keys); + bool check_keyslot_access(); bool test_rsa_keypair(const void *public_exponent, const void *private_exponent, const void *modulus); -bool test_eticket_rsa_keypair(const rsa_keypair_t *keypair); u32 rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size); +void derive_rsa_kek(u32 ks, key_storage_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option); + // Equivalent to spl::GenerateAesKek void generate_aes_kek(u32 ks, key_storage_t *keys, void *out_kek, const void *kek_source, u32 generation, u32 option); // Equivalent to spl::GenerateAesKey diff --git a/source/keys/es_crypto.c b/source/keys/es_crypto.c new file mode 100644 index 0000000..57b2912 --- /dev/null +++ b/source/keys/es_crypto.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "es_crypto.h" + +#include "../config.h" + +extern hekate_config h_cfg; + +bool test_eticket_rsa_keypair(const eticket_rsa_keypair_t *keypair) { + if (byte_swap_32(keypair->public_exponent) != RSA_PUBLIC_EXPONENT) + return false; + return test_rsa_keypair(&keypair->public_exponent, keypair->private_exponent, keypair->modulus); +} + +void es_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u32 generation, bool is_dev) { + if ((!h_cfg.t210b01 && !key_exists(keys->device_key)) || (h_cfg.t210b01 && (!key_exists(keys->master_key[0]) || !key_exists(keys->device_key_4x)))) { + return; + } + + const void *kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, eticket_rsa_kekek_source, kek_source, generation, option); +} + +void es_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek) { + if (!key_exists(keys->master_key[0])) { + return; + } + + const u32 generation = 0; + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, eticket_rsa_kekek_source, eticket_rsa_kek_source_legacy, generation, option); +} + +void es_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev) { + if (!key_exists(keys->master_key[0])) { + return; + } + + const void *kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; + const u32 generation = 0; + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, eticket_rsa_kekek_source, kek_source, generation, option); +} diff --git a/source/keys/es_crypto.h b/source/keys/es_crypto.h new file mode 100644 index 0000000..cc0fb95 --- /dev/null +++ b/source/keys/es_crypto.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ES_CRYPTO_H_ +#define _ES_CRYPTO_H_ + +#include "crypto.h" +#include "es_types.h" + +#include + +static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { + 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; +static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { + 0xBE, 0xC0, 0xBC, 0x8E, 0x75, 0xA0, 0xF6, 0x0C, 0x4A, 0x56, 0x64, 0x02, 0x3E, 0xD4, 0x9C, 0xD5}; +static const u8 eticket_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { + 0x88, 0x87, 0x50, 0x90, 0xA6, 0x2F, 0x75, 0x70, 0xA2, 0xD7, 0x71, 0x51, 0xAE, 0x6D, 0x39, 0x87}; +static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { + 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; + +bool test_eticket_rsa_keypair(const eticket_rsa_keypair_t *keypair); + +void es_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u32 generation, bool is_dev); +void es_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek); +void es_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev); + +#endif diff --git a/source/keys/es_types.h b/source/keys/es_types.h new file mode 100644 index 0000000..feb35fa --- /dev/null +++ b/source/keys/es_types.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ES_TYPES_H_ +#define _ES_TYPES_H_ + +#include +#include + +typedef struct { + u8 private_exponent[SE_RSA2048_DIGEST_SIZE]; + u8 modulus[SE_RSA2048_DIGEST_SIZE]; + u32 public_exponent; + u8 reserved[0xC]; +} eticket_rsa_keypair_t; + +#endif diff --git a/source/keys/fs_crypto.c b/source/keys/fs_crypto.c new file mode 100644 index 0000000..359237f --- /dev/null +++ b/source/keys/fs_crypto.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fs_crypto.h" + +#include "../config.h" +#include + +#include + +extern hekate_config h_cfg; + +void fs_derive_bis_keys(key_storage_t *keys, u8 out_bis_keys[4][32], u32 generation) { + if ((!h_cfg.t210b01 && !key_exists(keys->device_key)) || (h_cfg.t210b01 && (!key_exists(keys->master_key[0]) || !key_exists(keys->device_key_4x)))) { + return; + } + + generate_specific_aes_key(KS_AES_ECB, keys, out_bis_keys[0], bis_key_sources[0], generation); + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; + const u32 option = IS_DEVICE_UNIQUE; + generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); + generate_aes_key(KS_AES_ECB, keys, out_bis_keys[1], sizeof(bis_key_sources[1]), access_key, bis_key_sources[1]); + generate_aes_key(KS_AES_ECB, keys, out_bis_keys[2], sizeof(bis_key_sources[2]), access_key, bis_key_sources[2]); + memcpy(out_bis_keys[3], out_bis_keys[2], sizeof(bis_key_sources[2])); +} + +void fs_derive_header_key(key_storage_t *keys, void *out_key) { + if (!key_exists(keys->master_key[0])) { + return; + } + + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; + const u32 generation = 0; + const u32 option = NOT_DEVICE_UNIQUE; + generate_aes_kek(KS_AES_ECB, keys, access_key, header_kek_source, generation, option); + generate_aes_key(KS_AES_ECB, keys, out_key, sizeof(header_key_source), access_key, header_key_source); +} + +void fs_derive_key_area_key(key_storage_t *keys, void *out_key, u32 source_type, u32 generation) { + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; + const u32 option = NOT_DEVICE_UNIQUE; + generate_aes_kek(KS_AES_ECB, keys, access_key, key_area_key_sources[source_type], generation + 1, option); + load_aes_key(KS_AES_ECB, out_key, access_key, aes_key_generation_source); +} + +void fs_derive_save_mac_key(key_storage_t *keys, void *out_key) { + if ((!h_cfg.t210b01 && !key_exists(keys->device_key)) || (h_cfg.t210b01 && (!key_exists(keys->master_key[0]) || !key_exists(keys->device_key_4x)))) { + return; + } + + u32 access_key[SE_KEY_128_SIZE / 4] = {0}; + const u32 generation = 0; + const u32 option = IS_DEVICE_UNIQUE; + generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); + load_aes_key(KS_AES_ECB, out_key, access_key, save_mac_key_source); +} diff --git a/source/keys/fs_crypto.h b/source/keys/fs_crypto.h new file mode 100644 index 0000000..976ffde --- /dev/null +++ b/source/keys/fs_crypto.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FS_CRYPTO_H_ +#define _FS_CRYPTO_H_ + +#include "crypto.h" + +#include + +static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { + 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; +static const u8 bis_key_sources[3][0x20] __attribute__((aligned(4))) = { + {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, + 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, + {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, + 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, + {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, + 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} +}; + +static const u8 header_kek_source[0x10] __attribute__((aligned(4))) = { + 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}; +static const u8 header_key_source[0x20] __attribute__((aligned(4))) = { + 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, + 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}; + +static const u8 key_area_key_sources[3][0x10] __attribute__((aligned(4))) = { + {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application + {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean + {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system +}; + +static const u8 save_mac_kek_source[0x10] __attribute__((aligned(4))) = { + 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; +static const u8 save_mac_key_source[0x10] __attribute__((aligned(4))) = { + 0XE4, 0XCD, 0X3D, 0X4A, 0XD5, 0X0F, 0X74, 0X28, 0X45, 0XA4, 0X87, 0XE5, 0XA0, 0X63, 0XEA, 0X1F}; + +static const u8 save_mac_sd_card_kek_source[0x10] __attribute__((aligned(4))) = { + 0X04, 0X89, 0XEF, 0X5D, 0X32, 0X6E, 0X1A, 0X59, 0XC4, 0XB7, 0XAB, 0X8C, 0X36, 0X7A, 0XAB, 0X17}; +static const u8 save_mac_sd_card_key_source[0x10] __attribute__((aligned(4))) = { + 0X6F, 0X64, 0X59, 0X47, 0XC5, 0X61, 0X46, 0XF9, 0XFF, 0XA0, 0X45, 0XD5, 0X95, 0X33, 0X29, 0X18}; + +static const u8 sd_card_custom_storage_key_source[0x20] __attribute__((aligned(4))) = { + 0X37, 0X0C, 0X34, 0X5E, 0X12, 0XE4, 0XCE, 0XFE, 0X21, 0XB5, 0X8E, 0X64, 0XDB, 0X52, 0XAF, 0X35, + 0X4F, 0X2C, 0XA5, 0XA3, 0XFC, 0X99, 0X9A, 0X47, 0XC0, 0X3E, 0XE0, 0X04, 0X48, 0X5B, 0X2F, 0XD0}; +static const u8 sd_card_kek_source[0x10] __attribute__((aligned(4))) = { + 0X88, 0X35, 0X8D, 0X9C, 0X62, 0X9B, 0XA1, 0XA0, 0X01, 0X47, 0XDB, 0XE0, 0X62, 0X1B, 0X54, 0X32}; +static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = { + 0X58, 0X41, 0XA2, 0X84, 0X93, 0X5B, 0X56, 0X27, 0X8B, 0X8E, 0X1F, 0XC5, 0X18, 0XE9, 0X9F, 0X2B, + 0X67, 0XC7, 0X93, 0XF0, 0XF2, 0X4F, 0XDE, 0XD0, 0X75, 0X49, 0X5D, 0XCA, 0X00, 0X6D, 0X99, 0XC2}; +static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = { + 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, + 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; + +void fs_derive_bis_keys(key_storage_t *keys, u8 out_bis_keys[4][32], u32 generation); +void fs_derive_header_key(key_storage_t *keys, void *out_key); +void fs_derive_key_area_key(key_storage_t *keys, void *out_key, u32 source_type, u32 generation); +void fs_derive_save_mac_key(key_storage_t *keys, void *out_key); + +#endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 5d049f7..fa05e80 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -19,16 +19,6 @@ static const u8 null_hash[0x20] __attribute__((aligned(4))) = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; -static const u8 keyblob_key_sources[][0x10] __attribute__((aligned(4))) = { - {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 - {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 - {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 - {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 - {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 - {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 -}; - -//!TODO: Update on mkey changes. static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] __attribute__((aligned(4))) = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 @@ -39,9 +29,8 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0 {0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81}, //14.0.0 {0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67}, //15.0.0 -}; +}; //!TODO: Update on mkey changes. -//!TODO: Update on mkey changes. static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ @@ -58,9 +47,8 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */ {0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38}, /* Master key 0C encrypted with Master key 0D. */ {0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7}, /* Master key 0D encrypted with Master key 0E. */ -}; +}; //!TODO: Update on mkey changes. -//!TODO: Update on mkey changes. static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { {0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */ {0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */ @@ -77,7 +65,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr {0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */ {0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12}, /* Master key 0C encrypted with Master key 0D. */ {0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D}, /* Master key 0D encrypted with Master key 0E. */ -}; +}; //!TODO: Update on mkey changes. static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { {0x20, 0x9E, 0x97, 0xAE, 0xAF, 0x7E, 0x6A, 0xF6, 0x9E, 0xF5, 0xA7, 0x17, 0x2F, 0xF4, 0x49, 0xA6}, /* Zeroes encrypted with AES Class Key 00. */ @@ -96,16 +84,22 @@ static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { {0x95, 0x48, 0xC1, 0x59, 0x0F, 0x84, 0x19, 0xC4, 0xAB, 0x69, 0x05, 0x88, 0x01, 0x31, 0x52, 0x59}, /* Zeroes encrypted with Mariko BEK. */ }; -//======================================Keys======================================// -// from Package1 -> Secure_Monitor static const u8 package2_key_source[0x10] __attribute__((aligned(4))) = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; static const u8 titlekek_source[0x10] __attribute__((aligned(4))) = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -// from Package1ldr (or Secure_Monitor on 6.2.0+) +static const u8 keyblob_key_sources[][0x10] __attribute__((aligned(4))) = { + {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 + {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 + {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 + {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 + {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 + {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 +}; static const u8 keyblob_mac_key_source[0x10] __attribute__((aligned(4))) = { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; + static const u8 master_key_source[0x10] __attribute__((aligned(4))) = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; static const u8 per_console_key_source[0x10] __attribute__((aligned(4))) = { @@ -136,96 +130,3 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87}, // 14.0.0. {0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7}, // 15.0.0. }; //!TODO: Update on mkey changes. - -// from ES -static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { - 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; -static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { - 0xBE, 0xC0, 0xBC, 0x8E, 0x75, 0xA0, 0xF6, 0x0C, 0x4A, 0x56, 0x64, 0x02, 0x3E, 0xD4, 0x9C, 0xD5}; -static const u8 eticket_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { - 0x88, 0x87, 0x50, 0x90, 0xA6, 0x2F, 0x75, 0x70, 0xA2, 0xD7, 0x71, 0x51, 0xAE, 0x6D, 0x39, 0x87}; -static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { - 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; - -// from SSL -static const u8 ssl_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { - 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; -static const u8 ssl_rsa_kek_source[0x10] __attribute__((aligned(4))) = { - 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; -static const u8 ssl_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { - 0xD5, 0xD2, 0xFC, 0x00, 0xFD, 0x49, 0xDD, 0xF8, 0xEE, 0x7B, 0xC4, 0x4B, 0xE1, 0x4C, 0xAA, 0x99}; -static const u8 ssl_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { - 0xED, 0x36, 0xB1, 0x32, 0x27, 0x17, 0xD2, 0xB0, 0xBA, 0x1F, 0xC1, 0xBD, 0x4D, 0x38, 0x0F, 0x5E}; -static const u8 ssl_client_cert_kek_source[0x10] __attribute__((aligned(4))) = { - 0x64, 0xB8, 0x30, 0xDD, 0x0F, 0x3C, 0xB7, 0xFB, 0x4C, 0x16, 0x01, 0x97, 0xEA, 0x9D, 0x12, 0x10}; -static const u8 ssl_client_cert_key_source[0x10] __attribute__((aligned(4))) = { - 0x4D, 0x92, 0x5A, 0x69, 0x42, 0x23, 0xBB, 0x92, 0x59, 0x16, 0x3E, 0x51, 0x8C, 0x78, 0x14, 0x0F}; - -// from FS -static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { - 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_sources[3][0x20] __attribute__((aligned(4))) = { - {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, - 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, - {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, - 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, - {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, - 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} -}; -static const u8 header_kek_source[0x10] __attribute__((aligned(4))) = { - 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A}; -static const u8 header_key_source[0x20] __attribute__((aligned(4))) = { - 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, - 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2}; -static const u8 key_area_key_sources[3][0x10] __attribute__((aligned(4))) = { - {0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D}, // application - {0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82}, // ocean - {0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A}, // system -}; -static const u8 save_mac_kek_source[0x10] __attribute__((aligned(4))) = { - 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; -static const u8 save_mac_key_source[0x10] __attribute__((aligned(4))) = { - 0XE4, 0XCD, 0X3D, 0X4A, 0XD5, 0X0F, 0X74, 0X28, 0X45, 0XA4, 0X87, 0XE5, 0XA0, 0X63, 0XEA, 0X1F}; -static const u8 save_mac_sd_card_kek_source[0x10] __attribute__((aligned(4))) = { - 0X04, 0X89, 0XEF, 0X5D, 0X32, 0X6E, 0X1A, 0X59, 0XC4, 0XB7, 0XAB, 0X8C, 0X36, 0X7A, 0XAB, 0X17}; -static const u8 save_mac_sd_card_key_source[0x10] __attribute__((aligned(4))) = { - 0X6F, 0X64, 0X59, 0X47, 0XC5, 0X61, 0X46, 0XF9, 0XFF, 0XA0, 0X45, 0XD5, 0X95, 0X33, 0X29, 0X18}; -static const u8 sd_card_custom_storage_key_source[0x20] __attribute__((aligned(4))) = { - 0X37, 0X0C, 0X34, 0X5E, 0X12, 0XE4, 0XCE, 0XFE, 0X21, 0XB5, 0X8E, 0X64, 0XDB, 0X52, 0XAF, 0X35, - 0X4F, 0X2C, 0XA5, 0XA3, 0XFC, 0X99, 0X9A, 0X47, 0XC0, 0X3E, 0XE0, 0X04, 0X48, 0X5B, 0X2F, 0XD0}; -static const u8 sd_card_kek_source[0x10] __attribute__((aligned(4))) = { - 0X88, 0X35, 0X8D, 0X9C, 0X62, 0X9B, 0XA1, 0XA0, 0X01, 0X47, 0XDB, 0XE0, 0X62, 0X1B, 0X54, 0X32}; -static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = { - 0X58, 0X41, 0XA2, 0X84, 0X93, 0X5B, 0X56, 0X27, 0X8B, 0X8E, 0X1F, 0XC5, 0X18, 0XE9, 0X9F, 0X2B, - 0X67, 0XC7, 0X93, 0XF0, 0XF2, 0X4F, 0XDE, 0XD0, 0X75, 0X49, 0X5D, 0XCA, 0X00, 0X6D, 0X99, 0XC2}; -static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = { - 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, - 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; - -// from NFC -static const u8 nfc_key_source[0x10] __attribute__((aligned(4))) = { - 0x83, 0xF6, 0xEF, 0xD8, 0x13, 0x26, 0x49, 0xAB, 0x97, 0x5F, 0xEA, 0xBA, 0x65, 0x71, 0xCA, 0xCA}; -static const u8 encrypted_nfc_keys[0x80] __attribute__((aligned(4))) = { - 0x76, 0x50, 0x87, 0x02, 0x40, 0xA6, 0x5A, 0x98, 0xCE, 0x39, 0x2F, 0xC8, 0x83, 0xAF, 0x54, 0x76, - 0x28, 0xFF, 0x50, 0xFC, 0xC1, 0xFB, 0x26, 0x14, 0xA2, 0x4A, 0xA6, 0x74, 0x90, 0xA4, 0x37, 0x06, - 0x03, 0x63, 0xC2, 0xB1, 0xAF, 0x9F, 0xF7, 0x07, 0xFC, 0x8A, 0xB9, 0xCA, 0x28, 0x68, 0x6E, 0xF7, - 0x42, 0xCD, 0x68, 0x13, 0xCD, 0x7B, 0x3A, 0x60, 0x3E, 0x8B, 0xAB, 0x3A, 0xCC, 0xED, 0xE0, 0xDD, - 0x71, 0x1F, 0xA5, 0xDE, 0xB8, 0xB1, 0xF5, 0x1D, 0x14, 0x73, 0xBE, 0x27, 0xCC, 0xA1, 0x9B, 0x23, - 0x06, 0x91, 0x89, 0x05, 0xED, 0xD6, 0x92, 0x76, 0x3F, 0x42, 0xFB, 0xD1, 0x8F, 0x2D, 0x6D, 0x72, - 0xC8, 0x9E, 0x48, 0xE8, 0x03, 0x64, 0xF0, 0x3C, 0x0E, 0x2A, 0xF1, 0x26, 0x83, 0x02, 0x4F, 0xE2, - 0x41, 0xAA, 0xC8, 0x33, 0x68, 0x84, 0x3A, 0xFB, 0x87, 0x18, 0xEA, 0xF7, 0x36, 0xA2, 0x4E, 0xA9}; -static const u8 encrypted_nfc_keys_dev[0x80] __attribute__((aligned(4))) = { - 0x13, 0xB0, 0xFB, 0xC2, 0x91, 0x6D, 0x6E, 0x5A, 0x10, 0x31, 0x40, 0xB7, 0xDF, 0xCF, 0x69, 0x69, - 0xB0, 0xFA, 0xAE, 0x7F, 0xB2, 0x4D, 0x27, 0xC9, 0xE9, 0x3F, 0x5B, 0x38, 0x39, 0x24, 0x98, 0xCE, - 0xED, 0xD2, 0xA9, 0x6C, 0x6F, 0xA7, 0x72, 0xD7, 0x11, 0x31, 0x17, 0x93, 0x12, 0x49, 0x32, 0x85, - 0x21, 0xE5, 0xE1, 0x88, 0x0F, 0x08, 0xF2, 0x30, 0x5C, 0xC3, 0xAA, 0xFF, 0xC0, 0xAB, 0x21, 0x96, - 0x74, 0x39, 0xED, 0xE0, 0x5A, 0xB6, 0x75, 0xC2, 0x3B, 0x08, 0x61, 0xE4, 0xA7, 0xD6, 0xED, 0x8C, - 0xA9, 0x02, 0x12, 0xA6, 0xCC, 0x27, 0x4C, 0x1C, 0x41, 0x9C, 0xD8, 0x4C, 0x00, 0xC7, 0x5B, 0x5D, - 0xED, 0xC2, 0x3D, 0x5E, 0x00, 0xF5, 0x49, 0xFA, 0x6C, 0x75, 0x67, 0xCF, 0x1F, 0x73, 0x1A, 0xE8, - 0x47, 0xD4, 0x3D, 0x9B, 0x83, 0x5B, 0x18, 0x2F, 0x95, 0xA9, 0x04, 0xBC, 0x2E, 0xBB, 0x64, 0x4A}; -static const u8 nfc_blob_hash[0x20] __attribute__((aligned(4))) = { - 0x7F, 0x92, 0x83, 0x65, 0x4E, 0xC1, 0x09, 0x7F, 0xBD, 0xFF, 0x31, 0xDE, 0x94, 0x66, 0x51, 0xAE, - 0x60, 0xC2, 0x85, 0x4A, 0xFB, 0x54, 0x4A, 0xBE, 0x89, 0x63, 0xD3, 0x89, 0x63, 0x9C, 0x71, 0x0E}; -static const u8 nfc_blob_hash_dev[0x20] __attribute__((aligned(4))) = { - 0x4E, 0x36, 0x59, 0x1C, 0x75, 0x80, 0x23, 0x03, 0x98, 0x2D, 0x45, 0xD9, 0x85, 0xB8, 0x60, 0x18, - 0x7C, 0x85, 0x37, 0x9B, 0xCB, 0xBA, 0xF3, 0xDC, 0x25, 0x38, 0x73, 0xDB, 0x2F, 0xFA, 0xAE, 0x26}; diff --git a/source/keys/keys.c b/source/keys/keys.c index f7fc7c3..17ef755 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -17,9 +17,11 @@ #include "keys.h" #include "cal0_read.h" +#include "es_crypto.h" +#include "fs_crypto.h" #include "gmac.h" - -#include "../../keygen/tsec_keygen.h" +#include "nfc_crypto.h" +#include "ssl_crypto.h" #include "../config.h" #include @@ -35,9 +37,7 @@ #include #include #include -#include #include -#include #include #include "../storage/emummc.h" #include "../storage/nx_emmc.h" @@ -59,49 +59,49 @@ static u32 _key_count = 0, _titlekey_count = 0; static u32 start_time, end_time; u32 color_idx = 0; -// key functions -static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; }; -static void _save_key(const char *name, const void *data, u32 len, char *outbuf); -static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); +static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { + if (!key_exists(data)) + return; + u32 pos = strlen(outbuf); + pos += s_printf(&outbuf[pos], "%s = ", name); + for (u32 i = 0; i < len; i++) + pos += s_printf(&outbuf[pos], "%02x", *(u8*)(data + i)); + s_printf(&outbuf[pos], "\n"); + _key_count++; +} -static void _derive_master_key_mariko(key_storage_t *keys, bool is_dev) { +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { + char *temp_name = calloc(1, 0x40); + for (u32 i = 0; i < num_keys; i++) { + s_printf(temp_name, "%s_%02x", name, i + start_key); + _save_key(temp_name, data + i * len, len, outbuf); + } + free(temp_name); +} + +static void _derive_master_keys_mariko(key_storage_t *keys, bool is_dev) { minerva_periodic_training(); // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source); // Derive all master keys based on Mariko KEK for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) { // Relies on the Mariko KEK being properly set in slot 12 - se_aes_crypt_block_ecb(KS_MARIKO_KEK, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); + u32 kek_source_index = i - KB_FIRMWARE_VERSION_600; + const void *kek_source = is_dev ? &mariko_master_kek_sources_dev[kek_source_index] : &mariko_master_kek_sources[kek_source_index]; + se_aes_crypt_block_ecb(KS_MARIKO_KEK, DECRYPT, keys->master_kek[i], kek_source); load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } -static int _run_ams_keygen(key_storage_t *keys) { - tsec_ctxt_t tsec_ctxt; - tsec_ctxt.fw = tsec_keygen; - tsec_ctxt.size = sizeof(tsec_keygen); - tsec_ctxt.type = TSEC_FW_TYPE_NEW; - - u32 retries = 0; - while (tsec_query(keys->temp_key, &tsec_ctxt) < 0) { - retries++; - if (retries > 15) { - EPRINTF("Failed to run keygen."); - return -1; - } - } - - return 0; -} - static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev) { minerva_periodic_training(); if (!h_cfg.t210b01) { - u32 tsec_root_key_slot = is_dev ? 11 : 13; + u32 tsec_root_key_slot = is_dev ? KS_TSEC_ROOT_DEV : KS_TSEC_ROOT; // Derive all master keys based on current root key for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) { - se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); - load_aes_key(KS_AES_ECB, keys->master_key[i + KB_FIRMWARE_VERSION_620], keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_key_source); + u32 key_index = i + KB_FIRMWARE_VERSION_620; + se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[key_index], master_kek_sources[i]); + load_aes_key(KS_AES_ECB, keys->master_key[key_index], keys->master_kek[key_index], master_key_source); } } @@ -113,7 +113,7 @@ static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev } load_aes_key(KS_AES_ECB, keys->temp_key, keys->master_key[0], is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]); - if (_key_exists(keys->temp_key)) { + if (key_exists(keys->temp_key)) { EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod"); memset(keys->master_key, 0, sizeof(keys->master_key)); } @@ -176,7 +176,7 @@ static void _derive_keyblob_keys(key_storage_t *keys) { memcpy(keys->package1_key[i], keys->keyblob[i].package1_key, sizeof(keys->package1_key[i])); memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i])); - if (!_key_exists(keys->master_key[i])) { + if (!key_exists(keys->master_key[i])) { load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } @@ -186,67 +186,26 @@ static void _derive_keyblob_keys(key_storage_t *keys) { static void _derive_bis_keys(key_storage_t *keys) { minerva_periodic_training(); u32 generation = fuse_read_odm_keygen_rev(); - - if (!(_key_exists(keys->device_key) || (generation && _key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x)))) { - return; - } - generate_specific_aes_key(KS_AES_ECB, keys, &keys->bis_key[0], bis_key_sources[0], generation); - u32 access_key[SE_KEY_128_SIZE / 4] = {0}; - const u32 option = IS_DEVICE_UNIQUE; - generate_aes_kek(KS_AES_ECB, keys, access_key, bis_kek_source, generation, option); - generate_aes_key(KS_AES_ECB, keys, keys->bis_key[1], sizeof(keys->bis_key[1]), access_key, bis_key_sources[1]); - generate_aes_key(KS_AES_ECB, keys, keys->bis_key[2], sizeof(keys->bis_key[2]), access_key, bis_key_sources[2]); - memcpy(keys->bis_key[3], keys->bis_key[2], sizeof(keys->bis_key[3])); -} - -static void _derive_non_unique_keys(key_storage_t *keys, bool is_dev) { - minerva_periodic_training(); - if (_key_exists(keys->master_key[0])) { - const u32 generation = 0; - const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - generate_aes_kek(KS_AES_ECB, keys, keys->temp_key, header_kek_source, generation, option); - generate_aes_key(KS_AES_ECB, keys, keys->header_key, sizeof(keys->header_key), keys->temp_key, header_key_source); - } -} - -static void _derive_rsa_kek(u32 ks, key_storage_t *keys, void *out_rsa_kek, const void *kekek_source, const void *kek_source, u32 generation, u32 option) { - void *access_key = keys->temp_key; - generate_aes_kek(ks, keys, access_key, kekek_source, generation, option); - get_device_unique_data_key(ks, out_rsa_kek, access_key, kek_source); + fs_derive_bis_keys(keys, keys->bis_key, generation); } static void _derive_misc_keys(key_storage_t *keys, bool is_dev) { minerva_periodic_training(); - if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) { - void *access_key = keys->temp_key; - const u32 generation = 0; - const u32 option = IS_DEVICE_UNIQUE; - generate_aes_kek(KS_AES_ECB, keys, access_key, save_mac_kek_source, generation, option); - load_aes_key(KS_AES_ECB, keys->save_mac_key, access_key, save_mac_key_source); - } - - if (_key_exists(keys->master_key[0])) { - const void *eticket_kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; - const u32 generation = 0; - u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; - _derive_rsa_kek(KS_AES_ECB, keys, keys->eticket_rsa_kek, eticket_rsa_kekek_source, eticket_kek_source, generation, option); - - const void *ssl_kek_source = is_dev ? ssl_rsa_kek_source_dev : ssl_rsa_kek_source; - option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; - _derive_rsa_kek(KS_AES_ECB, keys, keys->ssl_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); - } + fs_derive_save_mac_key(keys, keys->save_mac_key); + es_derive_rsa_kek_original(keys, keys->eticket_rsa_kek, is_dev); + ssl_derive_rsa_kek_original(keys, keys->ssl_rsa_kek, is_dev); } -static void _derive_per_generation_keys(key_storage_t *keys) { +static void _derive_non_unique_keys(key_storage_t *keys) { + minerva_periodic_training(); + fs_derive_header_key(keys, keys->header_key); + for (u32 generation = 0; generation < ARRAY_SIZE(keys->master_key); generation++) { minerva_periodic_training(); - if (!_key_exists(keys->master_key[generation])) + if (!key_exists(keys->master_key[generation])) continue; for (u32 source_type = 0; source_type < ARRAY_SIZE(key_area_key_sources); source_type++) { - void *access_key = keys->temp_key; - const u32 option = GET_IS_DEVICE_UNIQUE(NOT_DEVICE_UNIQUE); - generate_aes_kek(KS_AES_ECB, keys, access_key, key_area_key_sources[source_type], generation + 1, option); - load_aes_key(KS_AES_ECB, keys->key_area_key[source_type][generation], access_key, aes_key_generation_source); + fs_derive_key_area_key(keys, keys->key_area_key[source_type][generation], source_type, generation); } load_aes_key(KS_AES_ECB, keys->package2_key[generation], keys->master_key[generation], package2_key_source); load_aes_key(KS_AES_ECB, keys->titlekek[generation], keys->master_key[generation], titlekek_source); @@ -292,7 +251,7 @@ static void _decode_tickets(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u3 } } -static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, rsa_keypair_t *rsa_keypair) { +static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, eticket_rsa_keypair_t *rsa_keypair) { FIL fp; u64 br = buf_size; u64 offset = 0; @@ -471,14 +430,12 @@ static bool _decrypt_ssl_rsa_key(key_storage_t *keys, titlekey_buffer_t *titleke return true; } - const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; + ssl_derive_rsa_kek_legacy(keys, keys->ssl_rsa_kek_legacy); ctr_key = keys->ssl_rsa_kek_legacy; - _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); enforce_unique = false; } else if (generation) { - const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; + ssl_derive_rsa_kek_device_unique(keys, keys->ssl_rsa_kek_personalized, generation); ctr_key = keys->ssl_rsa_kek_personalized; - _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); } else { ctr_key = keys->ssl_rsa_kek; } @@ -520,9 +477,9 @@ static bool _decrypt_eticket_rsa_key(key_storage_t *keys, titlekey_buffer_t *tit // Handle legacy case if (key_size == ETICKET_RSA_KEYPAIR_SIZE) { - const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; - ctr_key = keys->temp_key; - _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, eticket_rsa_kekek_source, eticket_rsa_kek_source_legacy, generation, option); + u32 temp_key[SE_KEY_128_SIZE / 4] = {0}; + es_derive_rsa_kek_legacy(keys, temp_key); + ctr_key = temp_key; se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); @@ -535,10 +492,8 @@ static bool _decrypt_eticket_rsa_key(key_storage_t *keys, titlekey_buffer_t *tit } if (generation) { - const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | IS_DEVICE_UNIQUE; + es_derive_rsa_kek_device_unique(keys, keys->eticket_rsa_kek_personalized, generation, is_dev); ctr_key = keys->eticket_rsa_kek_personalized; - const void *kek_source = is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source; - _derive_rsa_kek(KS_AES_ECB, keys, ctr_key, eticket_rsa_kekek_source, kek_source, generation, option); } else { ctr_key = keys->eticket_rsa_kek; } @@ -556,16 +511,12 @@ static bool _decrypt_eticket_rsa_key(key_storage_t *keys, titlekey_buffer_t *tit } static bool _derive_titlekeys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { - if (!_key_exists(keys->eticket_rsa_kek)) { + if (!key_exists(keys->eticket_rsa_kek)) { return false; } gfx_printf("%kTitlekeys... \n", colors[(color_idx++) % 6]); - if (!_decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev)) { - return false; - } - const u32 buf_size = SAVE_BLOCK_SIZE_DEFAULT; _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, NULL); _get_titlekeys_from_save(buf_size, keys->save_mac_key, titlekey_buffer, &keys->eticket_rsa_keypair); @@ -591,6 +542,17 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b EPRINTF("Unable to set partition."); return false; } + + bool res = _decrypt_ssl_rsa_key(keys, titlekey_buffer); + if (!res) { + EPRINTF("Unable to derive SSL key."); + } + + res =_decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev); + if (!res) { + EPRINTF("Unable to derive ETicket key."); + } + // Parse eMMC GPT LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &emmc_storage); @@ -616,11 +578,6 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b EPRINTF("Unable to get SD seed."); } - bool res = _decrypt_ssl_rsa_key(keys, titlekey_buffer); - if (!res) { - EPRINTF("Unable to derive SSL key."); - } - res = _derive_titlekeys(keys, titlekey_buffer, is_dev); if (!res) { EPRINTF("Unable to derive titlekeys."); @@ -660,7 +617,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { // Check if key is as expected if (ks < ARRAY_SIZE(mariko_key_vectors)) { se_aes_crypt_block_ecb(ks, DECRYPT, &data[0], mariko_key_vectors[ks]); - if (_key_exists(data)) { + if (key_exists(data)) { EPRINTFARGS("Failed to validate keyslot %d.", ks); continue; } @@ -858,19 +815,19 @@ static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_key key_storage_t *keys = is_dev ? dev_keys : prod_keys; if (h_cfg.t210b01) { - _derive_master_key_mariko(keys, is_dev); + _derive_master_keys_mariko(keys, is_dev); _derive_master_keys_from_latest_key(keys, is_dev); } else { - int res = _run_ams_keygen(keys); - if (res) { + if (run_ams_keygen(keys)) { + EPRINTF("Failed to run keygen."); return; } u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); free(aes_keys); _derive_master_keys_from_latest_key(prod_keys, false); @@ -916,17 +873,15 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); _derive_misc_keys(keys, is_dev); - _derive_non_unique_keys(&prod_keys, is_dev); - _derive_non_unique_keys(&dev_keys, is_dev); - _derive_per_generation_keys(&prod_keys); - _derive_per_generation_keys(&dev_keys); + _derive_non_unique_keys(&prod_keys); + _derive_non_unique_keys(&dev_keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; // Requires BIS key for SYSTEM partition if (!emmc_storage.initialized) { EPRINTF("eMMC not initialized.\nSkipping SD seed and titlekeys."); - } else if (_key_exists(keys->bis_key[2])) { + } else if (key_exists(keys->bis_key[2])) { _derive_emmc_keys(keys, titlekey_buffer, is_dev); } else { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); @@ -946,37 +901,6 @@ static void _derive_keys() { } } - static void _decrypt_amiibo_keys(key_storage_t *keys, const u8 *encrypted_keys, nfc_save_key_t nfc_save_keys[2]) { - u32 kek[SE_KEY_128_SIZE / 4] = {0}; - decrypt_aes_key(KS_AES_ECB, keys, kek, nfc_key_source, 0, 0); - - nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; - static const u8 nfc_iv[SE_KEY_128_SIZE] = { - 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; - se_aes_key_set(KS_AES_CTR, kek, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); - - minerva_periodic_training(); - - u32 xor_pad[0x20 / 4] = {0}; - se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); - - minerva_periodic_training(); - - memcpy(nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key)); - memcpy(nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase)); - nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed); - memcpy(nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed)); - memcpy(nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad)); - - memcpy(nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif)); - memcpy(nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif)); - nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif); - memcpy(nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif)); - memcpy(nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad)); - } - void derive_amiibo_keys() { minerva_change_freq(FREQ_1600); @@ -984,7 +908,6 @@ void derive_amiibo_keys() { key_storage_t __attribute__((aligned(4))) prod_keys = {0}, dev_keys = {0}; key_storage_t *keys = is_dev ? &dev_keys : &prod_keys; - const u8 *encrypted_keys = is_dev ? encrypted_nfc_keys_dev : encrypted_nfc_keys; _derive_master_keys(&prod_keys, &dev_keys, is_dev); @@ -998,7 +921,7 @@ void derive_amiibo_keys() { minerva_periodic_training(); - if (!_key_exists(keys->master_key[0])) { + if (!key_exists(keys->master_key[0])) { EPRINTF("Unable to derive master keys for NFC."); minerva_change_freq(FREQ_800); btn_wait(); @@ -1007,7 +930,7 @@ void derive_amiibo_keys() { nfc_save_key_t __attribute__((aligned(4))) nfc_save_keys[2] = {0}; - _decrypt_amiibo_keys(keys, encrypted_keys, nfc_save_keys); + nfc_decrypt_amiibo_keys(keys, nfc_save_keys, is_dev); minerva_periodic_training(); @@ -1073,23 +996,3 @@ void dump_keys() { } gfx_clear_grey(0x1B); } - -static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { - if (!_key_exists(data)) - return; - u32 pos = strlen(outbuf); - pos += s_printf(&outbuf[pos], "%s = ", name); - for (u32 i = 0; i < len; i++) - pos += s_printf(&outbuf[pos], "%02x", *(u8*)(data + i)); - s_printf(&outbuf[pos], "\n"); - _key_count++; -} - -static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { - char *temp_name = calloc(1, 0x40); - for (u32 i = 0; i < num_keys; i++) { - s_printf(temp_name, "%s_%02x", name, i + start_key); - _save_key(temp_name, data + i * len, len, outbuf); - } - free(temp_name); -} diff --git a/source/keys/keys.h b/source/keys/keys.h index 3f15719..622249e 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -62,27 +62,6 @@ typedef struct { u8 titlekeys[SZ_256K / 0x10][0x10]; } titlekey_buffer_t; -typedef struct { - char phrase[0xE]; - u8 seed[0xE]; - u8 hmac_key[0x10]; - char phrase_for_verif[0xE]; - u8 seed_for_verif[0x10]; - u8 hmac_key_for_verif[0x10]; - u8 ctr_key[0x10]; - u8 ctr_iv[0x10]; - u8 pad[6]; -} nfc_keyblob_t; - -typedef struct { - u8 hmac_key[0x10]; - char phrase[0xE]; - u8 rsvd; - u8 seed_size; - u8 seed[0x10]; - u8 xor_pad[0x20]; -} nfc_save_key_t; - typedef struct { char rights_id[0x20]; char equals[3]; diff --git a/source/keys/nfc_crypto.c b/source/keys/nfc_crypto.c new file mode 100644 index 0000000..078d5e7 --- /dev/null +++ b/source/keys/nfc_crypto.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "nfc_crypto.h" + +#include +#include + +#include + +void nfc_decrypt_amiibo_keys(key_storage_t *keys, nfc_save_key_t out_nfc_save_keys[2], bool is_dev) { + const u8 *encrypted_keys = is_dev ? encrypted_nfc_keys_dev : encrypted_nfc_keys; + u32 kek[SE_KEY_128_SIZE / 4] = {0}; + decrypt_aes_key(KS_AES_ECB, keys, kek, nfc_key_source, 0, 0); + + nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; + static const u8 nfc_iv[SE_KEY_128_SIZE] = { + 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; + se_aes_key_set(KS_AES_CTR, kek, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); + + minerva_periodic_training(); + + u32 xor_pad[0x20 / 4] = {0}; + se_aes_key_set(KS_AES_CTR, nfc_keyblob.ctr_key, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv); + + minerva_periodic_training(); + + memcpy(out_nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key)); + memcpy(out_nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase)); + out_nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed); + memcpy(out_nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed)); + memcpy(out_nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad)); + + memcpy(out_nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif)); + memcpy(out_nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif)); + out_nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif); + memcpy(out_nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif)); + memcpy(out_nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad)); +} diff --git a/source/keys/nfc_crypto.h b/source/keys/nfc_crypto.h new file mode 100644 index 0000000..26a1104 --- /dev/null +++ b/source/keys/nfc_crypto.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _NFC_CRYPTO_H_ +#define _NFC_CRYPTO_H_ + +#include "crypto.h" + +#include +#include + +static const u8 nfc_key_source[0x10] __attribute__((aligned(4))) = { + 0x83, 0xF6, 0xEF, 0xD8, 0x13, 0x26, 0x49, 0xAB, 0x97, 0x5F, 0xEA, 0xBA, 0x65, 0x71, 0xCA, 0xCA}; +static const u8 encrypted_nfc_keys[0x80] __attribute__((aligned(4))) = { + 0x76, 0x50, 0x87, 0x02, 0x40, 0xA6, 0x5A, 0x98, 0xCE, 0x39, 0x2F, 0xC8, 0x83, 0xAF, 0x54, 0x76, + 0x28, 0xFF, 0x50, 0xFC, 0xC1, 0xFB, 0x26, 0x14, 0xA2, 0x4A, 0xA6, 0x74, 0x90, 0xA4, 0x37, 0x06, + 0x03, 0x63, 0xC2, 0xB1, 0xAF, 0x9F, 0xF7, 0x07, 0xFC, 0x8A, 0xB9, 0xCA, 0x28, 0x68, 0x6E, 0xF7, + 0x42, 0xCD, 0x68, 0x13, 0xCD, 0x7B, 0x3A, 0x60, 0x3E, 0x8B, 0xAB, 0x3A, 0xCC, 0xED, 0xE0, 0xDD, + 0x71, 0x1F, 0xA5, 0xDE, 0xB8, 0xB1, 0xF5, 0x1D, 0x14, 0x73, 0xBE, 0x27, 0xCC, 0xA1, 0x9B, 0x23, + 0x06, 0x91, 0x89, 0x05, 0xED, 0xD6, 0x92, 0x76, 0x3F, 0x42, 0xFB, 0xD1, 0x8F, 0x2D, 0x6D, 0x72, + 0xC8, 0x9E, 0x48, 0xE8, 0x03, 0x64, 0xF0, 0x3C, 0x0E, 0x2A, 0xF1, 0x26, 0x83, 0x02, 0x4F, 0xE2, + 0x41, 0xAA, 0xC8, 0x33, 0x68, 0x84, 0x3A, 0xFB, 0x87, 0x18, 0xEA, 0xF7, 0x36, 0xA2, 0x4E, 0xA9}; +static const u8 encrypted_nfc_keys_dev[0x80] __attribute__((aligned(4))) = { + 0x13, 0xB0, 0xFB, 0xC2, 0x91, 0x6D, 0x6E, 0x5A, 0x10, 0x31, 0x40, 0xB7, 0xDF, 0xCF, 0x69, 0x69, + 0xB0, 0xFA, 0xAE, 0x7F, 0xB2, 0x4D, 0x27, 0xC9, 0xE9, 0x3F, 0x5B, 0x38, 0x39, 0x24, 0x98, 0xCE, + 0xED, 0xD2, 0xA9, 0x6C, 0x6F, 0xA7, 0x72, 0xD7, 0x11, 0x31, 0x17, 0x93, 0x12, 0x49, 0x32, 0x85, + 0x21, 0xE5, 0xE1, 0x88, 0x0F, 0x08, 0xF2, 0x30, 0x5C, 0xC3, 0xAA, 0xFF, 0xC0, 0xAB, 0x21, 0x96, + 0x74, 0x39, 0xED, 0xE0, 0x5A, 0xB6, 0x75, 0xC2, 0x3B, 0x08, 0x61, 0xE4, 0xA7, 0xD6, 0xED, 0x8C, + 0xA9, 0x02, 0x12, 0xA6, 0xCC, 0x27, 0x4C, 0x1C, 0x41, 0x9C, 0xD8, 0x4C, 0x00, 0xC7, 0x5B, 0x5D, + 0xED, 0xC2, 0x3D, 0x5E, 0x00, 0xF5, 0x49, 0xFA, 0x6C, 0x75, 0x67, 0xCF, 0x1F, 0x73, 0x1A, 0xE8, + 0x47, 0xD4, 0x3D, 0x9B, 0x83, 0x5B, 0x18, 0x2F, 0x95, 0xA9, 0x04, 0xBC, 0x2E, 0xBB, 0x64, 0x4A}; +static const u8 nfc_blob_hash[SE_SHA_256_SIZE] __attribute__((aligned(4))) = { + 0x7F, 0x92, 0x83, 0x65, 0x4E, 0xC1, 0x09, 0x7F, 0xBD, 0xFF, 0x31, 0xDE, 0x94, 0x66, 0x51, 0xAE, + 0x60, 0xC2, 0x85, 0x4A, 0xFB, 0x54, 0x4A, 0xBE, 0x89, 0x63, 0xD3, 0x89, 0x63, 0x9C, 0x71, 0x0E}; +static const u8 nfc_blob_hash_dev[SE_SHA_256_SIZE] __attribute__((aligned(4))) = { + 0x4E, 0x36, 0x59, 0x1C, 0x75, 0x80, 0x23, 0x03, 0x98, 0x2D, 0x45, 0xD9, 0x85, 0xB8, 0x60, 0x18, + 0x7C, 0x85, 0x37, 0x9B, 0xCB, 0xBA, 0xF3, 0xDC, 0x25, 0x38, 0x73, 0xDB, 0x2F, 0xFA, 0xAE, 0x26}; + +typedef struct { + char phrase[0xE]; + u8 seed[0xE]; + u8 hmac_key[0x10]; + char phrase_for_verif[0xE]; + u8 seed_for_verif[0x10]; + u8 hmac_key_for_verif[0x10]; + u8 ctr_key[0x10]; + u8 ctr_iv[0x10]; + u8 pad[6]; +} nfc_keyblob_t; + +typedef struct { + u8 hmac_key[0x10]; + char phrase[0xE]; + u8 rsvd; + u8 seed_size; + u8 seed[0x10]; + u8 xor_pad[0x20]; +} nfc_save_key_t; + +void nfc_decrypt_amiibo_keys(key_storage_t *keys, nfc_save_key_t out_nfc_save_keys[2], bool is_dev); + +#endif diff --git a/source/keys/ssl_crypto.c b/source/keys/ssl_crypto.c new file mode 100644 index 0000000..109627f --- /dev/null +++ b/source/keys/ssl_crypto.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ssl_crypto.h" + +#include "../config.h" + +extern hekate_config h_cfg; + +void ssl_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u32 generation) { + if ((!h_cfg.t210b01 && !key_exists(keys->device_key)) || (h_cfg.t210b01 && (!key_exists(keys->master_key[0]) || !key_exists(keys->device_key_4x)))) { + return; + } + + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_SSL_KEY) | IS_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, ssl_client_cert_kek_source, ssl_client_cert_key_source, generation, option); +} + +void ssl_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek) { + if (!key_exists(keys->master_key[0])) { + return; + } + + const u32 generation = 0; + const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, ssl_rsa_kekek_source, ssl_rsa_kek_source_legacy, generation, option); +} + +void ssl_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev) { + if (!key_exists(keys->master_key[0])) { + return; + } + + const void *ssl_kek_source = is_dev ? ssl_rsa_kek_source_dev : ssl_rsa_kek_source; + const u32 generation = 0; + u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; + derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); +} diff --git a/source/keys/ssl_crypto.h b/source/keys/ssl_crypto.h new file mode 100644 index 0000000..de462a6 --- /dev/null +++ b/source/keys/ssl_crypto.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SSL_CRYPTO_H_ +#define _SSL_CRYPTO_H_ + +#include "crypto.h" + +#include + +static const u8 ssl_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { + 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; +static const u8 ssl_rsa_kek_source[0x10] __attribute__((aligned(4))) = { + 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; +static const u8 ssl_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { + 0xD5, 0xD2, 0xFC, 0x00, 0xFD, 0x49, 0xDD, 0xF8, 0xEE, 0x7B, 0xC4, 0x4B, 0xE1, 0x4C, 0xAA, 0x99}; +static const u8 ssl_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { + 0xED, 0x36, 0xB1, 0x32, 0x27, 0x17, 0xD2, 0xB0, 0xBA, 0x1F, 0xC1, 0xBD, 0x4D, 0x38, 0x0F, 0x5E}; +static const u8 ssl_client_cert_kek_source[0x10] __attribute__((aligned(4))) = { + 0x64, 0xB8, 0x30, 0xDD, 0x0F, 0x3C, 0xB7, 0xFB, 0x4C, 0x16, 0x01, 0x97, 0xEA, 0x9D, 0x12, 0x10}; +static const u8 ssl_client_cert_key_source[0x10] __attribute__((aligned(4))) = { + 0x4D, 0x92, 0x5A, 0x69, 0x42, 0x23, 0xBB, 0x92, 0x59, 0x16, 0x3E, 0x51, 0x8C, 0x78, 0x14, 0x0F}; + +void ssl_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u32 generation); +void ssl_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek); +void ssl_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev); + +#endif From 1b2c829ca07ac1c4c2997b0fd0a6a45ab9a7682a Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Nov 2022 14:40:33 -0700 Subject: [PATCH 160/166] keys: Fix hex prefix capitalization --- source/keys/es_crypto.h | 4 ++-- source/keys/fs_crypto.h | 22 +++++++++++----------- source/keys/ssl_crypto.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/source/keys/es_crypto.h b/source/keys/es_crypto.h index cc0fb95..acca3f8 100644 --- a/source/keys/es_crypto.h +++ b/source/keys/es_crypto.h @@ -23,13 +23,13 @@ #include static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { - 0XDB, 0XA4, 0X51, 0X12, 0X4C, 0XA0, 0XA9, 0X83, 0X68, 0X14, 0XF5, 0XED, 0X95, 0XE3, 0X12, 0X5B}; + 0xDB, 0xA4, 0x51, 0x12, 0x4C, 0xA0, 0xA9, 0x83, 0x68, 0x14, 0xF5, 0xED, 0x95, 0xE3, 0x12, 0x5B}; static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { 0xBE, 0xC0, 0xBC, 0x8E, 0x75, 0xA0, 0xF6, 0x0C, 0x4A, 0x56, 0x64, 0x02, 0x3E, 0xD4, 0x9C, 0xD5}; static const u8 eticket_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { 0x88, 0x87, 0x50, 0x90, 0xA6, 0x2F, 0x75, 0x70, 0xA2, 0xD7, 0x71, 0x51, 0xAE, 0x6D, 0x39, 0x87}; static const u8 eticket_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { - 0X46, 0X6E, 0X57, 0XB7, 0X4A, 0X44, 0X7F, 0X02, 0XF3, 0X21, 0XCD, 0XE5, 0X8F, 0X2F, 0X55, 0X35}; + 0x46, 0x6E, 0x57, 0xB7, 0x4A, 0x44, 0x7F, 0x02, 0xF3, 0x21, 0xCD, 0xE5, 0x8F, 0x2F, 0x55, 0x35}; bool test_eticket_rsa_keypair(const eticket_rsa_keypair_t *keypair); diff --git a/source/keys/fs_crypto.h b/source/keys/fs_crypto.h index 976ffde..f8ccdf7 100644 --- a/source/keys/fs_crypto.h +++ b/source/keys/fs_crypto.h @@ -45,26 +45,26 @@ static const u8 key_area_key_sources[3][0x10] __attribute__((aligned(4))) = { }; static const u8 save_mac_kek_source[0x10] __attribute__((aligned(4))) = { - 0XD8, 0X9C, 0X23, 0X6E, 0XC9, 0X12, 0X4E, 0X43, 0XC8, 0X2B, 0X03, 0X87, 0X43, 0XF9, 0XCF, 0X1B}; + 0xD8, 0x9C, 0x23, 0x6E, 0xC9, 0x12, 0x4E, 0x43, 0xC8, 0x2B, 0x03, 0x87, 0x43, 0xF9, 0xCF, 0x1B}; static const u8 save_mac_key_source[0x10] __attribute__((aligned(4))) = { - 0XE4, 0XCD, 0X3D, 0X4A, 0XD5, 0X0F, 0X74, 0X28, 0X45, 0XA4, 0X87, 0XE5, 0XA0, 0X63, 0XEA, 0X1F}; + 0xE4, 0xCD, 0x3D, 0x4A, 0xD5, 0x0F, 0x74, 0x28, 0x45, 0xA4, 0x87, 0xE5, 0xA0, 0x63, 0xEA, 0x1F}; static const u8 save_mac_sd_card_kek_source[0x10] __attribute__((aligned(4))) = { - 0X04, 0X89, 0XEF, 0X5D, 0X32, 0X6E, 0X1A, 0X59, 0XC4, 0XB7, 0XAB, 0X8C, 0X36, 0X7A, 0XAB, 0X17}; + 0x04, 0x89, 0xEF, 0x5D, 0x32, 0x6E, 0x1A, 0x59, 0xC4, 0xB7, 0xAB, 0x8C, 0x36, 0x7A, 0xAB, 0x17}; static const u8 save_mac_sd_card_key_source[0x10] __attribute__((aligned(4))) = { - 0X6F, 0X64, 0X59, 0X47, 0XC5, 0X61, 0X46, 0XF9, 0XFF, 0XA0, 0X45, 0XD5, 0X95, 0X33, 0X29, 0X18}; + 0x6F, 0x64, 0x59, 0x47, 0xC5, 0x61, 0x46, 0xF9, 0xFF, 0xA0, 0x45, 0xD5, 0x95, 0x33, 0x29, 0x18}; static const u8 sd_card_custom_storage_key_source[0x20] __attribute__((aligned(4))) = { - 0X37, 0X0C, 0X34, 0X5E, 0X12, 0XE4, 0XCE, 0XFE, 0X21, 0XB5, 0X8E, 0X64, 0XDB, 0X52, 0XAF, 0X35, - 0X4F, 0X2C, 0XA5, 0XA3, 0XFC, 0X99, 0X9A, 0X47, 0XC0, 0X3E, 0XE0, 0X04, 0X48, 0X5B, 0X2F, 0XD0}; + 0x37, 0x0C, 0x34, 0x5E, 0x12, 0xE4, 0xCE, 0xFE, 0x21, 0xB5, 0x8E, 0x64, 0xDB, 0x52, 0xAF, 0x35, + 0x4F, 0x2C, 0xA5, 0xA3, 0xFC, 0x99, 0x9A, 0x47, 0xC0, 0x3E, 0xE0, 0x04, 0x48, 0x5B, 0x2F, 0xD0}; static const u8 sd_card_kek_source[0x10] __attribute__((aligned(4))) = { - 0X88, 0X35, 0X8D, 0X9C, 0X62, 0X9B, 0XA1, 0XA0, 0X01, 0X47, 0XDB, 0XE0, 0X62, 0X1B, 0X54, 0X32}; + 0x88, 0x35, 0x8D, 0x9C, 0x62, 0x9B, 0xA1, 0xA0, 0x01, 0x47, 0xDB, 0xE0, 0x62, 0x1B, 0x54, 0x32}; static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = { - 0X58, 0X41, 0XA2, 0X84, 0X93, 0X5B, 0X56, 0X27, 0X8B, 0X8E, 0X1F, 0XC5, 0X18, 0XE9, 0X9F, 0X2B, - 0X67, 0XC7, 0X93, 0XF0, 0XF2, 0X4F, 0XDE, 0XD0, 0X75, 0X49, 0X5D, 0XCA, 0X00, 0X6D, 0X99, 0XC2}; + 0x58, 0x41, 0xA2, 0x84, 0x93, 0x5B, 0x56, 0x27, 0x8B, 0x8E, 0x1F, 0xC5, 0x18, 0xE9, 0x9F, 0x2B, + 0x67, 0xC7, 0x93, 0xF0, 0xF2, 0x4F, 0xDE, 0xD0, 0x75, 0x49, 0x5D, 0xCA, 0x00, 0x6D, 0x99, 0xC2}; static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = { - 0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD, - 0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A}; + 0x24, 0x49, 0xB7, 0x22, 0x72, 0x67, 0x03, 0xA8, 0x19, 0x65, 0xE6, 0xE3, 0xEA, 0x58, 0x2F, 0xDD, + 0x9A, 0x95, 0x15, 0x17, 0xB1, 0x6E, 0x8F, 0x7F, 0x1F, 0x68, 0x26, 0x31, 0x52, 0xEA, 0x29, 0x6A}; void fs_derive_bis_keys(key_storage_t *keys, u8 out_bis_keys[4][32], u32 generation); void fs_derive_header_key(key_storage_t *keys, void *out_key); diff --git a/source/keys/ssl_crypto.h b/source/keys/ssl_crypto.h index de462a6..6d84784 100644 --- a/source/keys/ssl_crypto.h +++ b/source/keys/ssl_crypto.h @@ -22,9 +22,9 @@ #include static const u8 ssl_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { - 0X7F, 0X5B, 0XB0, 0X84, 0X7B, 0X25, 0XAA, 0X67, 0XFA, 0XC8, 0X4B, 0XE2, 0X3D, 0X7B, 0X69, 0X03}; + 0x7F, 0x5B, 0xB0, 0x84, 0x7B, 0x25, 0xAA, 0x67, 0xFA, 0xC8, 0x4B, 0xE2, 0x3D, 0x7B, 0x69, 0x03}; static const u8 ssl_rsa_kek_source[0x10] __attribute__((aligned(4))) = { - 0X9A, 0X38, 0X3B, 0XF4, 0X31, 0XD0, 0XBD, 0X81, 0X32, 0X53, 0X4B, 0XA9, 0X64, 0X39, 0X7D, 0XE3}; + 0x9A, 0x38, 0x3B, 0xF4, 0x31, 0xD0, 0xBD, 0x81, 0x32, 0x53, 0x4B, 0xA9, 0x64, 0x39, 0x7D, 0xE3}; static const u8 ssl_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { 0xD5, 0xD2, 0xFC, 0x00, 0xFD, 0x49, 0xDD, 0xF8, 0xEE, 0x7B, 0xC4, 0x4B, 0xE1, 0x4C, 0xAA, 0x99}; static const u8 ssl_rsa_kek_source_legacy[0x10] __attribute__((aligned(4))) = { From dcf4bca30cb3f9a82068dab21382957b29974053 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Nov 2022 15:41:16 -0700 Subject: [PATCH 161/166] keys: Move RSA functions out of keys.c --- source/keys/crypto.h | 13 ++- source/keys/es_crypto.c | 88 ++++++++++++++ source/keys/es_crypto.h | 9 ++ source/keys/es_types.h | 46 ++++++++ source/keys/key_sources.inl | 5 - source/keys/keys.c | 227 +++++++----------------------------- source/keys/keys.h | 46 -------- source/keys/ssl_crypto.c | 69 +++++++++++ source/keys/ssl_crypto.h | 4 + 9 files changed, 266 insertions(+), 241 deletions(-) diff --git a/source/keys/crypto.h b/source/keys/crypto.h index c242485..67195be 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -25,6 +25,11 @@ #include +// Sha256 hash of the null string. +static const u8 null_hash[0x20] __attribute__((aligned(4))) = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; @@ -103,6 +108,9 @@ static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { {0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E} }; + //!TODO: Update on keygen changes. +#define TSEC_ROOT_KEY_VERSION 2 + // Lockpick_RCM keyslots #define KS_BIS_00_CRYPT 0 #define KS_BIS_00_TWEAK 1 @@ -128,11 +136,6 @@ static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { #define RSA_PUBLIC_EXPONENT 65537 -#define SSL_RSA_KEY_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE) -#define ETICKET_RSA_KEYPAIR_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE * 2 + SE_KEY_128_SIZE) - -#define TICKET_SIG_TYPE_RSA2048_SHA256 0x10004 - typedef struct { u8 master_kek[SE_KEY_128_SIZE]; u8 data[0x70]; diff --git a/source/keys/es_crypto.c b/source/keys/es_crypto.c index 57b2912..f31b46a 100644 --- a/source/keys/es_crypto.c +++ b/source/keys/es_crypto.c @@ -16,7 +16,16 @@ #include "es_crypto.h" +#include "cal0_read.h" + #include "../config.h" +#include +#include "../gfx/tui.h" +#include +#include +#include + +#include extern hekate_config h_cfg; @@ -56,3 +65,82 @@ void es_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_ const u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_IMPORT_ES_DEVICE_KEY) | NOT_DEVICE_UNIQUE; derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, eticket_rsa_kekek_source, kek_source, generation, option); } + +bool decrypt_eticket_rsa_key(key_storage_t *keys, void *buffer, bool is_dev) { + if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, buffer)) { + return false; + } + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)buffer; + u32 generation = 0; + const void *encrypted_key = NULL; + const void *iv = NULL; + u32 key_size = 0; + void *ctr_key = NULL; + + if (!cal0_get_eticket_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { + return false; + } + + // Handle legacy case + if (key_size == ETICKET_RSA_KEYPAIR_SIZE) { + u32 temp_key[SE_KEY_128_SIZE / 4] = {0}; + es_derive_rsa_kek_legacy(keys, temp_key); + ctr_key = temp_key; + + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); + + if (test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + memcpy(keys->eticket_rsa_kek, ctr_key, sizeof(keys->eticket_rsa_kek)); + return true; + } + // Fall through and try usual method if not applicable + } + + if (generation) { + es_derive_rsa_kek_device_unique(keys, keys->eticket_rsa_kek_personalized, generation, is_dev); + ctr_key = keys->eticket_rsa_kek_personalized; + } else { + ctr_key = keys->eticket_rsa_kek; + } + + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); + + if (!test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { + EPRINTF("Invalid eticket keypair."); + memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); + return false; + } + + return true; +} + +void es_decode_tickets(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u32 remaining, u32 total, u32 *titlekey_count, u32 x, u32 y, u32 *pct, u32 *last_pct, bool is_personalized) { + ticket_t *curr_ticket = (ticket_t *)titlekey_buffer->read_buffer; + for (u32 i = 0; i < MIN(buf_size / sizeof(ticket_t), remaining) * sizeof(ticket_t) && curr_ticket->signature_type != 0; i += sizeof(ticket_t), curr_ticket++) { + minerva_periodic_training(); + *pct = (total - remaining) * 100 / total; + if (*pct > *last_pct && *pct <= 100) { + *last_pct = *pct; + tui_pbar(x, y, *pct, COLOR_GREEN, 0xFF155500); + } + + // This is in case an encrypted volatile ticket is left behind + if (curr_ticket->signature_type != TICKET_SIG_TYPE_RSA2048_SHA256) + continue; + + u8 *curr_titlekey = curr_ticket->titlekey_block; + const u32 block_size = SE_RSA2048_DIGEST_SIZE; + const u32 titlekey_size = sizeof(titlekey_buffer->titlekeys[0]); + if (is_personalized) { + se_rsa_exp_mod(0, curr_titlekey, block_size, curr_titlekey, block_size); + if (rsa_oaep_decode(curr_titlekey, titlekey_size, null_hash, sizeof(null_hash), curr_titlekey, block_size) != titlekey_size) + continue; + } + memcpy(titlekey_buffer->rights_ids[*titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); + memcpy(titlekey_buffer->titlekeys[*titlekey_count], curr_titlekey, titlekey_size); + (*titlekey_count)++; + } +} diff --git a/source/keys/es_crypto.h b/source/keys/es_crypto.h index acca3f8..03c777b 100644 --- a/source/keys/es_crypto.h +++ b/source/keys/es_crypto.h @@ -20,8 +20,13 @@ #include "crypto.h" #include "es_types.h" +#include #include +#define ETICKET_RSA_KEYPAIR_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE * 2 + SE_KEY_128_SIZE) + +#define TICKET_SIG_TYPE_RSA2048_SHA256 0x10004 + static const u8 eticket_rsa_kek_source[0x10] __attribute__((aligned(4))) = { 0xDB, 0xA4, 0x51, 0x12, 0x4C, 0xA0, 0xA9, 0x83, 0x68, 0x14, 0xF5, 0xED, 0x95, 0xE3, 0x12, 0x5B}; static const u8 eticket_rsa_kek_source_dev[0x10] __attribute__((aligned(4))) = { @@ -37,4 +42,8 @@ void es_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u32 void es_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek); void es_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev); +bool decrypt_eticket_rsa_key(key_storage_t *keys, void *buffer, bool is_dev); + +void es_decode_tickets(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u32 remaining, u32 total, u32 *titlekey_count, u32 x, u32 y, u32 *pct, u32 *last_pct, bool is_personalized); + #endif diff --git a/source/keys/es_types.h b/source/keys/es_types.h index feb35fa..2dca8dc 100644 --- a/source/keys/es_types.h +++ b/source/keys/es_types.h @@ -27,4 +27,50 @@ typedef struct { u8 reserved[0xC]; } eticket_rsa_keypair_t; +// only tickets of type Rsa2048Sha256 are expected +typedef struct { + u32 signature_type; // always 0x10004 + u8 signature[SE_RSA2048_DIGEST_SIZE]; + u8 sig_padding[0x3C]; + char issuer[0x40]; + u8 titlekey_block[SE_RSA2048_DIGEST_SIZE]; + u8 format_version; + u8 titlekey_type; + u16 ticket_version; + u8 license_type; + u8 common_key_id; + u16 property_mask; + u64 reserved; + u64 ticket_id; + u64 device_id; + u8 rights_id[0x10]; + u32 account_id; + u32 sect_total_size; + u32 sect_hdr_offset; + u16 sect_hdr_count; + u16 sect_hdr_entry_size; + u8 padding[0x140]; +} ticket_t; + +typedef struct { + u8 rights_id[0x10]; + u64 ticket_id; + u32 account_id; + u16 property_mask; + u16 reserved; +} ticket_record_t; + +typedef struct { + u8 read_buffer[SZ_256K]; + u8 rights_ids[SZ_256K / 0x10][0x10]; + u8 titlekeys[SZ_256K / 0x10][0x10]; +} titlekey_buffer_t; + +typedef struct { + char rights_id[0x20]; + char equals[3]; + char titlekey[0x20]; + char newline[1]; +} titlekey_text_buffer_t; + #endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index fa05e80..c03a4e1 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -14,11 +14,6 @@ * along with this program. If not, see . */ -// Sha256 hash of the null string. -static const u8 null_hash[0x20] __attribute__((aligned(4))) = { - 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, - 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; - static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620 + 1][0x10] __attribute__((aligned(4))) = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 diff --git a/source/keys/keys.c b/source/keys/keys.c index 17ef755..c8c8eae 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -16,10 +16,8 @@ #include "keys.h" -#include "cal0_read.h" #include "es_crypto.h" #include "fs_crypto.h" -#include "gmac.h" #include "nfc_crypto.h" #include "ssl_crypto.h" @@ -127,7 +125,7 @@ static void _derive_keyblob_keys(key_storage_t *keys) { bool have_keyblobs = true; if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { - u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); + u8 *aes_keys = (u8 *)calloc(1, SZ_4K); se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); memcpy(keys->sbk, aes_keys + 14 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); free(aes_keys); @@ -183,22 +181,47 @@ static void _derive_keyblob_keys(key_storage_t *keys) { free(keyblob_block); } +static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_keys, bool is_dev) { + key_storage_t *keys = is_dev ? dev_keys : prod_keys; + + if (h_cfg.t210b01) { + _derive_master_keys_mariko(keys, is_dev); + _derive_master_keys_from_latest_key(keys, is_dev); + } else { + if (run_ams_keygen(keys)) { + EPRINTF("Failed to run keygen."); + return; + } + + u8 *aes_keys = (u8 *)calloc(1, SZ_4K); + se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); + memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + free(aes_keys); + + _derive_master_keys_from_latest_key(prod_keys, false); + _derive_master_keys_from_latest_key(dev_keys, true); + _derive_keyblob_keys(keys); + } +} + static void _derive_bis_keys(key_storage_t *keys) { minerva_periodic_training(); u32 generation = fuse_read_odm_keygen_rev(); fs_derive_bis_keys(keys, keys->bis_key, generation); } -static void _derive_misc_keys(key_storage_t *keys, bool is_dev) { +static void _derive_misc_keys(key_storage_t *keys) { minerva_periodic_training(); fs_derive_save_mac_key(keys, keys->save_mac_key); - es_derive_rsa_kek_original(keys, keys->eticket_rsa_kek, is_dev); - ssl_derive_rsa_kek_original(keys, keys->ssl_rsa_kek, is_dev); } -static void _derive_non_unique_keys(key_storage_t *keys) { +static void _derive_non_unique_keys(key_storage_t *keys, bool is_dev) { minerva_periodic_training(); fs_derive_header_key(keys, keys->header_key); + es_derive_rsa_kek_original(keys, keys->eticket_rsa_kek, is_dev); + ssl_derive_rsa_kek_original(keys, keys->ssl_rsa_kek, is_dev); for (u32 generation = 0; generation < ARRAY_SIZE(keys->master_key); generation++) { minerva_periodic_training(); @@ -223,34 +246,6 @@ static bool _count_ticket_records(u32 buf_size, titlekey_buffer_t *titlekey_buff return false; } -static void _decode_tickets(u32 buf_size, titlekey_buffer_t *titlekey_buffer, u32 remaining, u32 total, u32 x, u32 y, u32 *pct, u32 *last_pct, bool is_personalized) { - ticket_t *curr_ticket = (ticket_t *)titlekey_buffer->read_buffer; - for (u32 i = 0; i < MIN(buf_size / sizeof(ticket_t), remaining) * sizeof(ticket_t) && curr_ticket->signature_type != 0; i += sizeof(ticket_t), curr_ticket++) { - minerva_periodic_training(); - *pct = (total - remaining) * 100 / total; - if (*pct > *last_pct && *pct <= 100) { - *last_pct = *pct; - tui_pbar(x, y, *pct, COLOR_GREEN, 0xFF155500); - } - - // This is in case an encrypted volatile ticket is left behind - if (curr_ticket->signature_type != TICKET_SIG_TYPE_RSA2048_SHA256) - continue; - - u8 *curr_titlekey = curr_ticket->titlekey_block; - const u32 block_size = SE_RSA2048_DIGEST_SIZE; - const u32 titlekey_size = sizeof(titlekey_buffer->titlekeys[0]); - if (is_personalized) { - se_rsa_exp_mod(0, curr_titlekey, block_size, curr_titlekey, block_size); - if (rsa_oaep_decode(curr_titlekey, titlekey_size, null_hash, sizeof(null_hash), curr_titlekey, block_size) != titlekey_size) - continue; - } - memcpy(titlekey_buffer->rights_ids[_titlekey_count], curr_ticket->rights_id, sizeof(titlekey_buffer->rights_ids[0])); - memcpy(titlekey_buffer->titlekeys[_titlekey_count], curr_titlekey, titlekey_size); - _titlekey_count++; - } -} - static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, titlekey_buffer_t *titlekey_buffer, eticket_rsa_keypair_t *rsa_keypair) { FIL fp; u64 br = buf_size; @@ -328,7 +323,7 @@ static bool _get_titlekeys_from_save(u32 buf_size, const u8 *save_mac_key, title if (!save_data_file_read(&ticket_file, &br, offset, titlekey_buffer->read_buffer, buf_size) || titlekey_buffer->read_buffer[0] == 0 || br != buf_size) break; offset += br; - _decode_tickets(buf_size, titlekey_buffer, remaining, file_tkey_count, save_x, save_y, &pct, &last_pct, is_personalized); + es_decode_tickets(buf_size, titlekey_buffer, remaining, file_tkey_count, &_titlekey_count, save_x, save_y, &pct, &last_pct, is_personalized); remaining -= MIN(buf_size / sizeof(ticket_t), remaining); } tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); @@ -382,7 +377,8 @@ static bool _derive_sd_seed(key_storage_t *keys) { } u8 read_buf[0x20] __attribute__((aligned(4))) = {0}; - // Skip the two header blocks and only check the first bytes of each block - file contents are always block-aligned + // Skip the two header blocks and only check the first bytes of each block + // File contents are always block-aligned for (u32 i = SAVE_BLOCK_SIZE_DEFAULT * 2; i < f_size(&fp); i += SAVE_BLOCK_SIZE_DEFAULT) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) break; @@ -398,120 +394,8 @@ static bool _derive_sd_seed(key_storage_t *keys) { return true; } -static bool _decrypt_ssl_rsa_key(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer) { - if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, titlekey_buffer->read_buffer)) { - return false; - } - - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - u32 generation = 0; - const void *encrypted_key = NULL; - const void *iv = NULL; - u32 key_size = 0; - void *ctr_key = NULL; - bool enforce_unique = true; - - if (!cal0_get_ssl_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { - return false; - } - - if (key_size == SSL_RSA_KEY_SIZE) { - bool all_zero = true; - const u8 *key8 = (const u8 *)encrypted_key; - for (u32 i = SE_RSA2048_DIGEST_SIZE; i < SSL_RSA_KEY_SIZE; i++) { - if (key8[i] != 0) { - all_zero = false; - break; - } - } - if (all_zero) { - // Keys of this form are not encrypted - memcpy(keys->ssl_rsa_key, encrypted_key, SE_RSA2048_DIGEST_SIZE); - return true; - } - - ssl_derive_rsa_kek_legacy(keys, keys->ssl_rsa_kek_legacy); - ctr_key = keys->ssl_rsa_kek_legacy; - enforce_unique = false; - } else if (generation) { - ssl_derive_rsa_kek_device_unique(keys, keys->ssl_rsa_kek_personalized, generation); - ctr_key = keys->ssl_rsa_kek_personalized; - } else { - ctr_key = keys->ssl_rsa_kek; - } - - u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; - se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, encrypted_key, ctr_size, iv); - - if (enforce_unique) { - u32 calc_mac[SE_KEY_128_SIZE / 4] = {0}; - calc_gmac(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, ctr_key, iv); - - const u8 *key8 = (const u8 *)encrypted_key; - if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { - EPRINTF("SSL keypair has invalid GMac."); - memset(keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); - return false; - } - } - - return true; -} - -static bool _decrypt_eticket_rsa_key(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { - if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, titlekey_buffer->read_buffer)) { - return false; - } - - nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer; - u32 generation = 0; - const void *encrypted_key = NULL; - const void *iv = NULL; - u32 key_size = 0; - void *ctr_key = NULL; - - if (!cal0_get_eticket_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { - return false; - } - - // Handle legacy case - if (key_size == ETICKET_RSA_KEYPAIR_SIZE) { - u32 temp_key[SE_KEY_128_SIZE / 4] = {0}; - es_derive_rsa_kek_legacy(keys, temp_key); - ctr_key = temp_key; - - se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); - - if (test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { - memcpy(keys->eticket_rsa_kek, ctr_key, sizeof(keys->eticket_rsa_kek)); - return true; - } - // Fall through and try usual method if not applicable - } - - if (generation) { - es_derive_rsa_kek_device_unique(keys, keys->eticket_rsa_kek_personalized, generation, is_dev); - ctr_key = keys->eticket_rsa_kek_personalized; - } else { - ctr_key = keys->eticket_rsa_kek; - } - - se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); - se_aes_crypt_ctr(KS_AES_CTR, &keys->eticket_rsa_keypair, sizeof(keys->eticket_rsa_keypair), encrypted_key, sizeof(keys->eticket_rsa_keypair), iv); - - if (!test_eticket_rsa_keypair(&keys->eticket_rsa_keypair)) { - EPRINTF("Invalid eticket keypair."); - memset(&keys->eticket_rsa_keypair, 0, sizeof(keys->eticket_rsa_keypair)); - return false; - } - - return true; -} - static bool _derive_titlekeys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { - if (!key_exists(keys->eticket_rsa_kek)) { + if (!key_exists(&keys->eticket_rsa_keypair)) { return false; } @@ -543,12 +427,12 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b return false; } - bool res = _decrypt_ssl_rsa_key(keys, titlekey_buffer); + bool res = decrypt_ssl_rsa_key(keys, titlekey_buffer); if (!res) { EPRINTF("Unable to derive SSL key."); } - res =_decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev); + res = decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev); if (!res) { EPRINTF("Unable to derive ETicket key."); } @@ -611,7 +495,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { u32 pos = 0; u32 zeros[SE_KEY_128_SIZE / 4] = {0}; u8 *data = malloc(4 * SE_KEY_128_SIZE); - char *text_buffer = calloc(1, 0x100 * count); + char *text_buffer = calloc(count, 0x100); for (u32 ks = start; ks < start + count; ks++) { // Check if key is as expected @@ -688,14 +572,13 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) { } static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { - char *text_buffer = NULL; if (!sd_mount()) { EPRINTF("Unable to mount SD."); return; } u32 text_buffer_size = MAX(_titlekey_count * sizeof(titlekey_text_buffer_t) + 1, SZ_16K); - text_buffer = (char *)calloc(1, text_buffer_size); + char *text_buffer = (char *)calloc(1, text_buffer_size); SAVE_KEY(aes_kek_generation_source); SAVE_KEY(aes_key_generation_source); @@ -765,9 +648,8 @@ static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_bu SAVE_KEY(titlekek_source); SAVE_KEY_VAR(tsec_key, keys->tsec_key); - const u32 root_key_ver = 2; char root_key_name[21] = "tsec_root_key_00"; - s_printf(root_key_name + 14, "%02x", root_key_ver); + s_printf(root_key_name + 14, "%02x", TSEC_ROOT_KEY_VERSION); _save_key(root_key_name, keys->tsec_root_key, SE_KEY_128_SIZE, text_buffer); gfx_printf("\n%k Found %d %s keys.\n\n", colors[(color_idx++) % 6], _key_count, is_dev ? "dev" : "prod"); @@ -811,31 +693,6 @@ static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_bu free(text_buffer); } -static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_keys, bool is_dev) { - key_storage_t *keys = is_dev ? dev_keys : prod_keys; - - if (h_cfg.t210b01) { - _derive_master_keys_mariko(keys, is_dev); - _derive_master_keys_from_latest_key(keys, is_dev); - } else { - if (run_ams_keygen(keys)) { - EPRINTF("Failed to run keygen."); - return; - } - - u8 *aes_keys = (u8 *)calloc(SZ_4K, 1); - se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); - memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - free(aes_keys); - - _derive_master_keys_from_latest_key(prod_keys, false); - _derive_master_keys_from_latest_key(dev_keys, true); - _derive_keyblob_keys(keys); - } -} - static void _derive_keys() { minerva_periodic_training(); @@ -872,9 +729,9 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - _derive_misc_keys(keys, is_dev); - _derive_non_unique_keys(&prod_keys); - _derive_non_unique_keys(&dev_keys); + _derive_misc_keys(keys); + _derive_non_unique_keys(&prod_keys, is_dev); + _derive_non_unique_keys(&dev_keys, is_dev); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; diff --git a/source/keys/keys.h b/source/keys/keys.h index 622249e..f8a84c1 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -23,52 +23,6 @@ #include #include -// only tickets of type Rsa2048Sha256 are expected -typedef struct { - u32 signature_type; // always 0x10004 - u8 signature[SE_RSA2048_DIGEST_SIZE]; - u8 sig_padding[0x3C]; - char issuer[0x40]; - u8 titlekey_block[SE_RSA2048_DIGEST_SIZE]; - u8 format_version; - u8 titlekey_type; - u16 ticket_version; - u8 license_type; - u8 common_key_id; - u16 property_mask; - u64 reserved; - u64 ticket_id; - u64 device_id; - u8 rights_id[0x10]; - u32 account_id; - u32 sect_total_size; - u32 sect_hdr_offset; - u16 sect_hdr_count; - u16 sect_hdr_entry_size; - u8 padding[0x140]; -} ticket_t; - -typedef struct { - u8 rights_id[0x10]; - u64 ticket_id; - u32 account_id; - u16 property_mask; - u16 reserved; -} ticket_record_t; - -typedef struct { - u8 read_buffer[SZ_256K]; - u8 rights_ids[SZ_256K / 0x10][0x10]; - u8 titlekeys[SZ_256K / 0x10][0x10]; -} titlekey_buffer_t; - -typedef struct { - char rights_id[0x20]; - char equals[3]; - char titlekey[0x20]; - char newline[1]; -} titlekey_text_buffer_t; - #define TPRINTF(text) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", end_time - start_time); \ diff --git a/source/keys/ssl_crypto.c b/source/keys/ssl_crypto.c index 109627f..b6b235b 100644 --- a/source/keys/ssl_crypto.c +++ b/source/keys/ssl_crypto.c @@ -16,7 +16,15 @@ #include "ssl_crypto.h" +#include "cal0_read.h" +#include "gmac.h" + #include "../config.h" +#include +#include +#include + +#include extern hekate_config h_cfg; @@ -49,3 +57,64 @@ void ssl_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is u32 option = SET_SEAL_KEY_INDEX(SEAL_KEY_DECRYPT_DEVICE_UNIQUE_DATA) | NOT_DEVICE_UNIQUE; derive_rsa_kek(KS_AES_ECB, keys, out_rsa_kek, ssl_rsa_kekek_source, ssl_kek_source, generation, option); } + +bool decrypt_ssl_rsa_key(key_storage_t *keys, void *buffer) { + if (!cal0_read(KS_BIS_00_TWEAK, KS_BIS_00_CRYPT, buffer)) { + return false; + } + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)buffer; + u32 generation = 0; + const void *encrypted_key = NULL; + const void *iv = NULL; + u32 key_size = 0; + void *ctr_key = NULL; + bool enforce_unique = true; + + if (!cal0_get_ssl_rsa_key(cal0, &encrypted_key, &key_size, &iv, &generation)) { + return false; + } + + if (key_size == SSL_RSA_KEY_SIZE) { + bool all_zero = true; + const u8 *key8 = (const u8 *)encrypted_key; + for (u32 i = SE_RSA2048_DIGEST_SIZE; i < SSL_RSA_KEY_SIZE; i++) { + if (key8[i] != 0) { + all_zero = false; + break; + } + } + if (all_zero) { + // Keys of this form are not encrypted + memcpy(keys->ssl_rsa_key, encrypted_key, SE_RSA2048_DIGEST_SIZE); + return true; + } + + ssl_derive_rsa_kek_legacy(keys, keys->ssl_rsa_kek_legacy); + ctr_key = keys->ssl_rsa_kek_legacy; + enforce_unique = false; + } else if (generation) { + ssl_derive_rsa_kek_device_unique(keys, keys->ssl_rsa_kek_personalized, generation); + ctr_key = keys->ssl_rsa_kek_personalized; + } else { + ctr_key = keys->ssl_rsa_kek; + } + + u32 ctr_size = enforce_unique ? key_size - 0x20 : key_size - 0x10; + se_aes_key_set(KS_AES_CTR, ctr_key, SE_KEY_128_SIZE); + se_aes_crypt_ctr(KS_AES_CTR, keys->ssl_rsa_key, ctr_size, encrypted_key, ctr_size, iv); + + if (enforce_unique) { + u32 calc_mac[SE_KEY_128_SIZE / 4] = {0}; + calc_gmac(KS_AES_ECB, calc_mac, keys->ssl_rsa_key, ctr_size, ctr_key, iv); + + const u8 *key8 = (const u8 *)encrypted_key; + if (memcmp(calc_mac, &key8[ctr_size], 0x10) != 0) { + EPRINTF("SSL keypair has invalid GMac."); + memset(keys->ssl_rsa_key, 0, sizeof(keys->ssl_rsa_key)); + return false; + } + } + + return true; +} diff --git a/source/keys/ssl_crypto.h b/source/keys/ssl_crypto.h index 6d84784..830fd45 100644 --- a/source/keys/ssl_crypto.h +++ b/source/keys/ssl_crypto.h @@ -21,6 +21,8 @@ #include +#define SSL_RSA_KEY_SIZE (SE_AES_IV_SIZE + SE_RSA2048_DIGEST_SIZE) + static const u8 ssl_rsa_kekek_source[0x10] __attribute__((aligned(4))) = { 0x7F, 0x5B, 0xB0, 0x84, 0x7B, 0x25, 0xAA, 0x67, 0xFA, 0xC8, 0x4B, 0xE2, 0x3D, 0x7B, 0x69, 0x03}; static const u8 ssl_rsa_kek_source[0x10] __attribute__((aligned(4))) = { @@ -38,4 +40,6 @@ void ssl_derive_rsa_kek_device_unique(key_storage_t *keys, void *out_rsa_kek, u3 void ssl_derive_rsa_kek_legacy(key_storage_t *keys, void *out_rsa_kek); void ssl_derive_rsa_kek_original(key_storage_t *keys, void *out_rsa_kek, bool is_dev); +bool decrypt_ssl_rsa_key(key_storage_t *keys, void *buffer); + #endif From 43be4ef19f9179b24d95c566bd92e1eca678c49e Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Nov 2022 16:40:15 -0700 Subject: [PATCH 162/166] keys: Make more readability tweaks --- source/keys/crypto.c | 5 ++-- source/keys/crypto.h | 16 +++++++----- source/keys/keys.c | 61 ++++++++++++++++++++------------------------ 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/source/keys/crypto.c b/source/keys/crypto.c index 46a7564..3e766c1 100644 --- a/source/keys/crypto.c +++ b/source/keys/crypto.c @@ -35,14 +35,15 @@ int key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0; } -int run_ams_keygen(key_storage_t *keys) { +int run_ams_keygen() { tsec_ctxt_t tsec_ctxt; tsec_ctxt.fw = tsec_keygen; tsec_ctxt.size = sizeof(tsec_keygen); tsec_ctxt.type = TSEC_FW_TYPE_NEW; u32 retries = 0; - while (tsec_query(keys->temp_key, &tsec_ctxt) < 0) { + u32 temp_key[SE_KEY_128_SIZE / 4]; + while (tsec_query(temp_key, &tsec_ctxt) < 0) { retries++; if (retries > 15) { return -1; diff --git a/source/keys/crypto.h b/source/keys/crypto.h index 67195be..4ea954f 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -21,6 +21,7 @@ #include "../hos/hos.h" #include +#include "../storage/nx_emmc.h" #include #include @@ -136,17 +137,20 @@ static const u8 secure_data_tweaks[1][0x10] __attribute__((aligned(4))) = { #define RSA_PUBLIC_EXPONENT 65537 +#define KEYBLOB_UNK_DATA_SIZE 0x70 +#define KEYBLOB_UNUSED_SIZE (NX_EMMC_BLOCKSIZE - SE_AES_CMAC_DIGEST_SIZE - SE_AES_IV_SIZE - sizeof(keyblob_t)) + typedef struct { u8 master_kek[SE_KEY_128_SIZE]; - u8 data[0x70]; + u8 data[KEYBLOB_UNK_DATA_SIZE]; u8 package1_key[SE_KEY_128_SIZE]; } keyblob_t; typedef struct { - u8 cmac[0x10]; - u8 iv[0x10]; + u8 cmac[SE_AES_CMAC_DIGEST_SIZE]; + u8 iv[SE_AES_IV_SIZE]; keyblob_t key_data; - u8 unused[0x150]; + u8 unused[KEYBLOB_UNUSED_SIZE]; } encrypted_keyblob_t; typedef struct { @@ -177,7 +181,7 @@ typedef struct { titlekek[KB_FIRMWARE_VERSION_MAX + 1][SE_KEY_128_SIZE], tsec_key[SE_KEY_128_SIZE], tsec_root_key[SE_KEY_128_SIZE]; - u32 sbk[4]; + u32 secure_boot_key[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; eticket_rsa_keypair_t eticket_rsa_keypair; } key_storage_t; @@ -203,7 +207,7 @@ typedef enum { int key_exists(const void *data); -int run_ams_keygen(key_storage_t *keys); +int run_ams_keygen(); bool check_keyslot_access(); diff --git a/source/keys/keys.c b/source/keys/keys.c index c8c8eae..511aef5 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -120,33 +120,28 @@ static void _derive_master_keys_from_latest_key(key_storage_t *keys, bool is_dev static void _derive_keyblob_keys(key_storage_t *keys) { minerva_periodic_training(); - u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); - u32 keyblob_mac[SE_KEY_128_SIZE / 4] = {0}; + encrypted_keyblob_t *keyblob_buffer = (encrypted_keyblob_t *)calloc(KB_FIRMWARE_VERSION_600 + 1, sizeof(encrypted_keyblob_t)); + u32 keyblob_mac[SE_AES_CMAC_DIGEST_SIZE / 4] = {0}; bool have_keyblobs = true; - if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) { - u8 *aes_keys = (u8 *)calloc(1, SZ_4K); - se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); - memcpy(keys->sbk, aes_keys + 14 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - free(aes_keys); - } else { - keys->sbk[0] = FUSE(FUSE_PRIVATE_KEY0); - keys->sbk[1] = FUSE(FUSE_PRIVATE_KEY1); - keys->sbk[2] = FUSE(FUSE_PRIVATE_KEY2); - keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); + if (FUSE(FUSE_PRIVATE_KEY0) != 0xFFFFFFFF) { + keys->secure_boot_key[0] = FUSE(FUSE_PRIVATE_KEY0); + keys->secure_boot_key[1] = FUSE(FUSE_PRIVATE_KEY1); + keys->secure_boot_key[2] = FUSE(FUSE_PRIVATE_KEY2); + keys->secure_boot_key[3] = FUSE(FUSE_PRIVATE_KEY3); } if (!emmc_storage.initialized) { have_keyblobs = false; - } else if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { + } else if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_buffer)) { EPRINTF("Unable to read keyblobs."); have_keyblobs = false; } else { have_keyblobs = true; } - encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; - for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { + encrypted_keyblob_t *current_keyblob = keyblob_buffer; + for (u32 i = 0; i < ARRAY_SIZE(keyblob_key_sources); i++, current_keyblob++) { minerva_periodic_training(); se_aes_crypt_block_ecb(KS_TSEC, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); se_aes_crypt_block_ecb(KS_SECURE_BOOT, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); @@ -178,7 +173,7 @@ static void _derive_keyblob_keys(key_storage_t *keys) { load_aes_key(KS_AES_ECB, keys->master_key[i], keys->master_kek[i], master_key_source); } } - free(keyblob_block); + free(keyblob_buffer); } static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_keys, bool is_dev) { @@ -188,7 +183,7 @@ static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_key _derive_master_keys_mariko(keys, is_dev); _derive_master_keys_from_latest_key(keys, is_dev); } else { - if (run_ams_keygen(keys)) { + if (run_ams_keygen()) { EPRINTF("Failed to run keygen."); return; } @@ -196,8 +191,13 @@ static void _derive_master_keys(key_storage_t *prod_keys, key_storage_t *dev_key u8 *aes_keys = (u8 *)calloc(1, SZ_4K); se_get_aes_keys(aes_keys + SZ_2K, aes_keys, SE_KEY_128_SIZE); memcpy(&dev_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT_DEV * SE_KEY_128_SIZE, SE_KEY_128_SIZE); - memcpy(keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&dev_keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&prod_keys->tsec_key, aes_keys + KS_TSEC * SE_KEY_128_SIZE, SE_KEY_128_SIZE); memcpy(&prod_keys->tsec_root_key, aes_keys + KS_TSEC_ROOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + if (FUSE(FUSE_PRIVATE_KEY0) != 0xFFFFFFFF) { + memcpy(&dev_keys->secure_boot_key, aes_keys + KS_SECURE_BOOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(&prod_keys->secure_boot_key, aes_keys + KS_SECURE_BOOT * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + } free(aes_keys); _derive_master_keys_from_latest_key(prod_keys, false); @@ -410,7 +410,7 @@ static bool _derive_titlekeys(key_storage_t *keys, titlekey_buffer_t *titlekey_b return true; } -static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { +static void _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_buffer, bool is_dev) { // Set BIS keys. // PRODINFO/PRODINFOF se_aes_key_set(KS_BIS_00_CRYPT, keys->bis_key[0] + 0x00, SE_KEY_128_SIZE); @@ -424,16 +424,14 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b if (!emummc_storage_set_mmc_partition(EMMC_GPP)) { EPRINTF("Unable to set partition."); - return false; + return; } - bool res = decrypt_ssl_rsa_key(keys, titlekey_buffer); - if (!res) { + if (!decrypt_ssl_rsa_key(keys, titlekey_buffer)) { EPRINTF("Unable to derive SSL key."); } - res = decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev); - if (!res) { + if (!decrypt_eticket_rsa_key(keys, titlekey_buffer, is_dev)) { EPRINTF("Unable to derive ETicket key."); } @@ -445,7 +443,7 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b if (!system_part) { EPRINTF("Unable to locate System partition."); nx_emmc_gpt_free(&gpt); - return false; + return; } nx_emmc_bis_init(system_part); @@ -453,7 +451,7 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b if (f_mount(&emmc_fs, "bis:", 1)) { EPRINTF("Unable to mount system partition."); nx_emmc_gpt_free(&gpt); - return false; + return; } if (!sd_mount()) { @@ -462,15 +460,12 @@ static bool _derive_emmc_keys(key_storage_t *keys, titlekey_buffer_t *titlekey_b EPRINTF("Unable to get SD seed."); } - res = _derive_titlekeys(keys, titlekey_buffer, is_dev); - if (!res) { + if (!_derive_titlekeys(keys, titlekey_buffer, is_dev)) { EPRINTF("Unable to derive titlekeys."); } f_mount(NULL, "bis:", 1); nx_emmc_gpt_free(&gpt); - - return res; } // The security engine supports partial key override for locked keyslots @@ -611,9 +606,9 @@ static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_bu SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); if (is_dev) { - SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources_dev, 5); + SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources_dev, KB_FIRMWARE_VERSION_600); } else { - SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources, 5); + SAVE_KEY_FAMILY_VAR(mariko_master_kek_source, mariko_master_kek_sources, KB_FIRMWARE_VERSION_600); } SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); SAVE_KEY_FAMILY_VAR(master_kek_source, master_kek_sources, KB_FIRMWARE_VERSION_620); @@ -634,7 +629,7 @@ static void _save_keys_to_sd(key_storage_t *keys, titlekey_buffer_t *titlekey_bu SAVE_KEY(sd_card_nca_key_source); SAVE_KEY(sd_card_save_key_source); SAVE_KEY_VAR(sd_seed, keys->sd_seed); - SAVE_KEY_VAR(secure_boot_key, keys->sbk); + SAVE_KEY_VAR(secure_boot_key, keys->secure_boot_key); SAVE_KEY_VAR(ssl_rsa_kek, keys->ssl_rsa_kek); SAVE_KEY_VAR(ssl_rsa_kek_personalized, keys->ssl_rsa_kek_personalized); if (is_dev) { From ffea336ecce54f4c3dcecbb9c72b2fa7f4abd228 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 5 Nov 2022 16:47:21 -0700 Subject: [PATCH 163/166] keys: Use SE size definitions --- source/keys/crypto.h | 2 +- source/keys/nfc_crypto.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/keys/crypto.h b/source/keys/crypto.h index 4ea954f..f4bf14f 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -27,7 +27,7 @@ #include // Sha256 hash of the null string. -static const u8 null_hash[0x20] __attribute__((aligned(4))) = { +static const u8 null_hash[SE_SHA_256_SIZE] __attribute__((aligned(4))) = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; diff --git a/source/keys/nfc_crypto.c b/source/keys/nfc_crypto.c index 078d5e7..b6caa5e 100644 --- a/source/keys/nfc_crypto.c +++ b/source/keys/nfc_crypto.c @@ -27,7 +27,7 @@ void nfc_decrypt_amiibo_keys(key_storage_t *keys, nfc_save_key_t out_nfc_save_ke decrypt_aes_key(KS_AES_ECB, keys, kek, nfc_key_source, 0, 0); nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob; - static const u8 nfc_iv[SE_KEY_128_SIZE] = { + static const u8 nfc_iv[SE_AES_IV_SIZE] = { 0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8}; se_aes_key_set(KS_AES_CTR, kek, SE_KEY_128_SIZE); se_aes_crypt_ctr(KS_AES_CTR, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv); From fb6b966bd65db7612ff640c85698e737dcf6d016 Mon Sep 17 00:00:00 2001 From: shchmue Date: Sun, 6 Nov 2022 17:59:36 -0800 Subject: [PATCH 164/166] Bump version to v1.9.9 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index eafbd19..dd0b543 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,5 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 8 +LPVERSION_BUGFX := 9 LPVERSION_RSVD := 0 From b5be83652cb119c25bb83c08686918c12bebd67d Mon Sep 17 00:00:00 2001 From: FlyingBananaTree <74322834+FlyingBananaTree@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:10:17 +0000 Subject: [PATCH 165/166] Support 16.0.0 keys --- source/hos/hos.h | 3 ++- source/keys/crypto.h | 3 +++ source/keys/key_sources.inl | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/hos/hos.h b/source/hos/hos.h index 9663d07..17d9a56 100644 --- a/source/hos/hos.h +++ b/source/hos/hos.h @@ -35,6 +35,7 @@ #define KB_FIRMWARE_VERSION_1300 12 #define KB_FIRMWARE_VERSION_1400 13 #define KB_FIRMWARE_VERSION_1500 14 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1500 //!TODO: Update on mkey changes. +#define KB_FIRMWARE_VERSION_1600 15 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1600 //!TODO: Update on mkey changes. #endif diff --git a/source/keys/crypto.h b/source/keys/crypto.h index f4bf14f..f2da17d 100644 --- a/source/keys/crypto.h +++ b/source/keys/crypto.h @@ -53,6 +53,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */ {0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2}, /* 14.0.0 Device Master Kek Source. */ {0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49}, /* 15.0.0 Device Master Kek Source. */ + {0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F}, /* 16.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -68,6 +69,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */ {0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA}, /* 14.0.0 Device Master Kek Source. */ {0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E}, /* 15.0.0 Device Master Kek Source. */ + {0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F}, /* 16.0.0 Device Master Kek Source. */ }; //!TODO: Update on mkey changes. static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = { @@ -83,6 +85,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI {0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */ {0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D}, /* 14.0.0 Device Master Key Source Source. */ {0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6}, /* 15.0.0 Device Master Key Source Source. */ + {0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C}, /* 16.0.0 Device Master Key Source Source. */ }; //!TODO: Update on mkey changes. static const u8 seal_key_masks[][0x10] __attribute__((aligned(4))) = { diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index c03a4e1..042ffbb 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -24,6 +24,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION {0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0 {0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81}, //14.0.0 {0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67}, //15.0.0 + {0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6}, //16.0.0 }; //!TODO: Update on mkey changes. static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { @@ -42,6 +43,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut {0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */ {0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38}, /* Master key 0C encrypted with Master key 0D. */ {0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7}, /* Master key 0D encrypted with Master key 0E. */ + {0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16}, /* Master key 0E encrypted with Master key 0F. */ }; //!TODO: Update on mkey changes. static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribute__((aligned(4))) = { @@ -60,6 +62,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr {0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */ {0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12}, /* Master key 0C encrypted with Master key 0D. */ {0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D}, /* Master key 0D encrypted with Master key 0E. */ + {0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26}, /* Master key 0E encrypted with Master key 0F. */ }; //!TODO: Update on mkey changes. static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = { @@ -112,6 +115,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_ {0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6}, // 13.0.0. {0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A}, // 14.0.0. {0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D}, // 15.0.0. + {0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9}, // 16.0.0. }; //!TODO: Update on mkey changes. static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = { {0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0. @@ -124,4 +128,5 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW {0x4D, 0x5A, 0xB2, 0xC9, 0xE9, 0xE4, 0x4E, 0xA4, 0xD3, 0xBF, 0x94, 0x12, 0x36, 0x30, 0xD0, 0x7F}, // 13.0.0. {0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87}, // 14.0.0. {0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7}, // 15.0.0. + {0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6}, // 16.0.0. }; //!TODO: Update on mkey changes. From d625847124652ee8a69bc335adcbdf8be144b4f8 Mon Sep 17 00:00:00 2001 From: shchmue Date: Wed, 22 Feb 2023 16:18:38 -0800 Subject: [PATCH 166/166] Bump version to v1.9.10 --- Versions.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.inc b/Versions.inc index dd0b543..5733cf3 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,5 +1,5 @@ # LP Version. LPVERSION_MAJOR := 1 LPVERSION_MINOR := 9 -LPVERSION_BUGFX := 9 +LPVERSION_BUGFX := 10 LPVERSION_RSVD := 0