Compare commits

..

7 Commits

Author SHA1 Message Date
Kostas Missos
4f2bbbf101 Fix GPU on Linux when booting from warmboot 2019-02-12 00:46:06 +02:00
Kostas Missos
b677d6cad3 Add max77620-rtc driver & disable alarm on shut off 2019-02-12 00:45:27 +02:00
Kostas Missos
b3f8961e45 Fix sleep with 6.X.X secmon when debug mode is on 2019-02-12 00:42:22 +02:00
Kostas Missos
2f37811aba Normalize brom patches & add sd autocalib fallback 2019-02-12 00:40:40 +02:00
Kostas Missos
5cd596e53c Add SVC generic patches
First patch allows same process on svcControlCodeMemory
2019-02-12 00:36:24 +02:00
Kostas Missos
4ae42c3a9d Small fixes and whitespace
Additionally make info functions smaller and show available fuses.
2019-02-12 00:34:35 +02:00
Kostas Missos
e105634b0d Proper warmboot exploit impl and documentation
Side effect:
Fixed a bug where the dumped patched bootrom had the warmboot exploit patch

Co-Authored-By: Balázs Triszka <balika011@gmail.com>
2018-12-17 21:10:13 +02:00
23 changed files with 323 additions and 74 deletions

View File

@@ -53,6 +53,7 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
ini.o \
ianos.o \
smmu.o \
max77620-rtc.o \
)
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \

View File

@@ -54,6 +54,9 @@ extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_st
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
#pragma GCC push_options
#pragma GCC optimize ("Os")
void print_fuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
@@ -77,7 +80,7 @@ void print_fuseinfo()
break;
}
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf(&gfx_con, "Burnt fuses: %d\n", burntFuses);
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
@@ -704,3 +707,6 @@ void bootrom_ipatches_info()
btn_wait();
}
}
#pragma GCC pop_options

View File

@@ -553,8 +553,10 @@ void fix_battery_desync()
}*/
/*
//#include "../modules/hekate_libsys_minerva/mtc.h"
//mtc_config_t mtc_cfg;
#include "../modules/hekate_libsys_minerva/mtc.h"
#include "../ianos/ianos.h"
#include "../soc/fuse.h"
mtc_config_t mtc_cfg;
void minerva()
{
@@ -582,6 +584,9 @@ void minerva()
break;
}
// Change DRAM voltage.
//i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 42); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
mtc_cfg.rate_to = 800000;
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
@@ -590,7 +595,7 @@ void minerva()
// Thefollowing frequency needs periodic training every 100ms.
//msleep(200);
//mtc_cfg.rate_to = 1600000;
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);

View File

@@ -23,5 +23,6 @@ void fix_sd_all_attr();
void fix_sd_nin_attr();
void fix_battery_desync();
void menu_autorcm();
//void minerva();
#endif

View File

@@ -238,6 +238,10 @@
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_V_OFFSET 0x808
#define DC_WINBUF_SURFACE_KIND 0x80B
#define PITCH (0 << 0)
#define TILED (1 << 0)
#define BLOCK (2 << 0)
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
/*! Display serial interface registers. */
#define _DSIREG(reg) ((reg) * 4)

View File

@@ -15,13 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "di.h"
#include "tui.h"
#include "../utils/btn.h"
#include "../config/config.h"
#include "../power/max17050.h"
#include "../utils/util.h"
#include "../config/config.h"
#include "di.h"
#ifdef MENU_LOGO_ENABLE
extern u8 *Kc_MENU_LOGO;

View File

@@ -487,6 +487,8 @@ int hos_launch(ini_sec_t *cfg)
for (u32 j = 0; j < kernel_patchset[i].val; j++)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
}
else if (kernel_patchset[i].id < SVC_VERIFY_DS)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
}
}
}
@@ -503,7 +505,9 @@ int hos_launch(ini_sec_t *cfg)
{
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
while(1) {} // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
_free_launch_components(&ctxt);
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
}
// Rebuild and encrypt package2.

View File

@@ -68,10 +68,18 @@ PATCHSET_DEF(_secmon_5_patchset,
PATCHSET_DEF(_secmon_6_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() }, //Sections SHA2.
// Fix sleep mode for debug.
{ 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
{ 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
{ 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
{ 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
{ 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
{ 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
{ 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_secmon_620_patchset,
@@ -79,7 +87,15 @@ PATCHSET_DEF(_secmon_620_patchset,
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
{ 0xDC8 + 0x610, _NOP() }, //Version.
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
{ 0xDC8 + 0xF10, _NOP() }, //Sections SHA2.
// Fix sleep mode for debug.
{ 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
{ 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
{ 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
{ 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
{ 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
{ 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
{ 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_warmboot_1_patchset,

View File

@@ -219,6 +219,7 @@ KERNEL_PATCHSET_DEF(_kernel_4_patchset,
);
KERNEL_PATCHSET_DEF(_kernel_5_patchset,
{ SVC_GENERIC, 0x38C2C, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
@@ -233,6 +234,7 @@ KERNEL_PATCHSET_DEF(_kernel_5_patchset,
);
KERNEL_PATCHSET_DEF(_kernel_6_patchset,
{ SVC_GENERIC, 0x3A8CC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
@@ -571,7 +573,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
memcpy(&hdr, ki->kip1, sizeof(hdr));
unsigned int newKipSize = sizeof(hdr);
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
@@ -584,7 +586,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
pkg2_kip1_t* newKip = malloc(newKipSize);
unsigned char* dstDataPtr = newKip->data;
const unsigned char* srcDataPtr = ki->kip1->data;
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// Easy copy path for uncompressed or ones we dont want to uncompress.
@@ -638,7 +640,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
char* patches[MAX_NUM_PATCHES_REQUESTED];
u32 numPatches=1;
u32 numPatches = 1;
patches[0] = patchNames;
{
for (char* p = patchNames; *p != 0; p++)
@@ -646,7 +648,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (*p == ',')
{
*p = 0;
patches[numPatches++] = p+1;
patches[numPatches++] = p + 1;
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
return "too_many_patches";
}
@@ -656,10 +658,10 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
u32 patchesApplied = 0; // Bitset over patches.
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
// Eliminate leading spaces.
for (const char* p=patches[i]; *p!=0; p++)
for (const char* p = patches[i]; *p != 0; p++)
{
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
patches[i]++;
@@ -671,7 +673,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
continue;
// Eliminate trailing spaces.
for (int chIdx=valueLen-1; chIdx>=0; chIdx--)
for (int chIdx=valueLen - 1; chIdx >= 0; chIdx--)
{
const char* p = patches[i] + chIdx;
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
@@ -684,11 +686,11 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
DPRINTF("Requested patch: '%s'\n", patches[i]);
}
u32 shaBuf[32/sizeof(u32)];
u32 shaBuf[32 / sizeof(u32)];
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
{
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
for (u32 currKipIdx=0; currKipIdx<(sizeof(_kip_ids)/sizeof(_kip_ids[0])); currKipIdx++)
for (u32 currKipIdx = 0; currKipIdx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])); currKipIdx++)
{
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
continue;
@@ -697,7 +699,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
if (strcmp(currPatchset->name, patches[i]) != 0)
{
@@ -728,7 +730,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
{
if (currPatchset->patches != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
@@ -752,13 +754,13 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
memset(shaBuf, 0, sizeof(shaBuf));
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime)/1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime) / 1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
#endif
currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
@@ -772,7 +774,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
unsigned char* kipSectData = ki->kip1->data;
for (u32 currSectIdx=0; currSectIdx<KIP1_NUM_SECTIONS; currSectIdx++)
for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS; currSectIdx++)
{
if (bitsAffected & (1u << currSectIdx))
{
@@ -806,7 +808,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
}
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
if ((patchesApplied & (1u << i)) == 0)
return patches[i];

View File

@@ -44,8 +44,10 @@ typedef struct _kernel_patch_t
enum
{
// Generic instruction patches
SVC_VERIFY_DS = 0x10, // 0x0-0xF are RESERVED.
// Always applied.
SVC_GENERIC = 0,
// Generic instruction patches.
SVC_VERIFY_DS = 0x10,
DEBUG_MODE_EN,
ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.

View File

@@ -84,7 +84,7 @@ void ianos_print_error(int errorno)
gfx_printf(&gfx_con, "Error loading ELF!\n");
break;
case 5:
gfx_printf(&gfx_con, "Error relcating ELF!\n");
gfx_printf(&gfx_con, "Error relocating ELF!\n");
break;
}
}

View File

@@ -31,6 +31,7 @@
#include "mem/heap.h"
#include "mem/sdram.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
#include "soc/hw_init.h"
#include "soc/i2c.h"
#include "soc/pmc.h"
@@ -229,6 +230,10 @@ void reboot_rcm()
void power_off()
{
sd_unmount();
// Stop the alarm, in case we injected and powered off too fast.
max77620_rtc_stop_alarm();
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
@@ -243,6 +248,10 @@ void check_power_off_from_hos()
if (hosWakeup & MAX77620_IRQ_TOP_RTC_MASK)
{
sd_unmount();
// Stop the alarm, in case we injected too fast.
max77620_rtc_stop_alarm();
if (h_cfg.autohosoff == 1)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
@@ -1148,6 +1157,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();
//Pivot the stack so we have enough space.
@@ -1165,7 +1175,7 @@ void ipl_main()
set_default_configuration();
// Save sdram lp0 config.
if (ianos_loader(true, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params()))
if (ianos_loader(true, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params_patched()))
h_cfg.errors |= ERR_LIBSYS_LP0;
display_init();

View File

@@ -18,11 +18,11 @@
#include "../soc/t210.h"
#include "mc.h"
#include "emc.h"
#include "sdram_param_t210.h"
#include "../soc/pmc.h"
#include "../utils/util.h"
#include "../soc/fuse.h"
#include "../power/max77620.h"
#include "../mem/sdram_param_t210.h"
#include "../soc/clock.h"
#define CONFIG_SDRAM_COMPRESS_CFG
@@ -388,9 +388,9 @@ break_nosleep:
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
if (params->boot_rom_patch_control & 0x80000000)
if (params->boot_rom_patch_control & (1 << 31))
{
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
}
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
@@ -489,19 +489,47 @@ break_nosleep:
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
}
const void *sdram_get_params()
sdram_params_t *sdram_get_params()
{
//TODO: sdram_id should be in [0, 7].
#ifdef CONFIG_SDRAM_COMPRESS_CFG
u8 *buf = (u8 *)0x40030000;
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
return (const void *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
#else
return _dram_cfgs[_get_sdram_id()];
#endif
}
/*
* Function: sdram_get_params_patched
*
* This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again.
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
* (The MSB falls out when it gets multiplied by sizeof(u32)).
* Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
* 0x10459E is the address where it returns an error when the signature is not valid.
* We change that to MOV R0, #0, so we pass the check.
*
* Note: The modulus in the header must match and validated.
*/
sdram_params_t *sdram_get_params_patched()
{
#define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff))
sdram_params_t *sdram_params = sdram_get_params();
// Disable Warmboot signature check.
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
return sdram_params;
}
void sdram_init()
{
//TODO: sdram_id should be in [0,4].

View File

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

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -172,7 +171,7 @@ static const u8 _dram_cfg_0[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -333,7 +332,7 @@ static const u8 _dram_cfg_1[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -494,7 +493,7 @@ static const u8 _dram_cfg_2[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -655,7 +654,7 @@ static const u8 _dram_cfg_3[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -816,7 +815,7 @@ static const u8 _dram_cfg_4[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -977,7 +976,7 @@ static const u8 _dram_cfg_5[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1138,7 +1137,7 @@ static const u8 _dram_cfg_6[1896] = {
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,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -15,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
static const u8 _dram_cfg_lz[1270] = {
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,
@@ -104,22 +103,22 @@ static const u8 _dram_cfg_lz[1270] = {
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, 0x00, 0x00, 0x00,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x17, 0x10, 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
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
};

View File

@@ -1,8 +1,8 @@
/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* Copyright (C) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,

View File

@@ -0,0 +1,77 @@
/*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "max77620-rtc.h"
#include "../soc/i2c.h"
#include "../utils/util.h"
void max77620_rtc_get_time(rtc_time_t *time)
{
u8 val = 0;
// Update RTC regs from RTC clock.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
// Get control reg config.
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);
// TODO: Check for binary format also?
// Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12;
// Get day of week. 1: Monday to 7: Sunday.
time->weekday = 0;
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG);
for (int i = 0; i < 8; i++)
{
time->weekday++;
if (val & 1)
break;
val >>= 1;
}
// Get date.
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
}
void max77620_rtc_stop_alarm()
{
u8 val = 0;
// Update RTC regs from RTC clock.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
// Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2.
for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++)
{
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i);
val &= ~MAX77620_RTC_ALARM_EN_MASK;
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val);
}
// Update RTC clock from RTC regs.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
}

View File

@@ -0,0 +1,75 @@
/*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MFD_MAX77620_RTC_H_
#define _MFD_MAX77620_RTC_H_
#include "../utils/types.h"
#define MAX77620_RTC_I2C_ADDR 0x68
#define MAX77620_RTC_NR_TIME_REGS 7
#define MAX77620_RTC_CONTROLM_REG 0x02
#define MAX77620_RTC_CONTROL_REG 0x03
#define MAX77620_RTC_BIN_FORMAT (1 << 0)
#define MAX77620_RTC_24H (1 << 1)
#define MAX77620_RTC_UPDATE0_REG 0x04
#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
#define MAX77620_RTC_READ_UPDATE (1 << 4)
#define MAX77620_RTC_SEC_REG 0x07
#define MAX77620_RTC_MIN_REG 0x08
#define MAX77620_RTC_HOUR_REG 0x09
#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
#define MAX77620_RTC_WEEKDAY_REG 0x0A
#define MAX77620_RTC_MONTH_REG 0x0B
#define MAX77620_RTC_YEAR_REG 0x0C
#define MAX77620_RTC_DATE_REG 0x0D
#define MAX77620_ALARM1_SEC_REG 0x0E
#define MAX77620_ALARM1_MIN_REG 0x0F
#define MAX77620_ALARM1_HOUR_REG 0x10
#define MAX77620_ALARM1_WEEKDAY_REG 0x11
#define MAX77620_ALARM1_MONTH_REG 0x12
#define MAX77620_ALARM1_YEAR_REG 0x13
#define MAX77620_ALARM1_DATE_REG 0x14
#define MAX77620_ALARM2_SEC_REG 0x15
#define MAX77620_ALARM2_MIN_REG 0x16
#define MAX77620_ALARM2_HOUR_REG 0x17
#define MAX77620_ALARM2_WEEKDAY_REG 0x18
#define MAX77620_ALARM2_MONTH_REG 0x19
#define MAX77620_ALARM2_YEAR_REG 0x1A
#define MAX77620_ALARM2_DATE_REG 0x1B
#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
typedef struct _rtc_time_t {
u8 weekday;
u8 sec;
u8 min;
u8 hour;
u8 date;
u8 month;
u16 year;
} rtc_time_t;
void max77620_rtc_get_time(rtc_time_t *time);
void max77620_rtc_stop_alarm();
#endif /* _MFD_MAX77620_RTC_H_ */

View File

@@ -22,11 +22,11 @@
/* clock_t: reset, enable, source, index, clk_src, clk_div */
static const clock_t _clock_uart[] = {
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
/* UART D */ { 0 },
/* UART E */ { 0 }
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
/* UART D */ { 0 },
/* UART E */ { 0 }
};
static const clock_t _clock_i2c[] = {

View File

@@ -247,6 +247,10 @@ void reconfig_hw_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);
// Fix GPU after warmboot for Linux.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
}
// Power off display.

View File

@@ -107,6 +107,8 @@
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68

View File

@@ -143,8 +143,20 @@ static int _sdmmc_get_clkcon(sdmmc_t *sdmmc)
static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
{
_sdmmc_get_clkcon(sdmmc);
if (sdmmc->id == SDMMC_4)
*(vu32 *)0x70000AB4 = ((*(vu32 *)0x70000AB4) & 0x3FFC) | 0x1040;
switch (sdmmc->id)
{
case SDMMC_1:
if (power == SDMMC_POWER_OFF)
break;
if (power == SDMMC_POWER_1_8)
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4.
else if (power == SDMMC_POWER_3_3)
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8.
break;
case SDMMC_4:
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040;
break;
}
//TODO: load standard values for other controllers, can depend on power.
}