Compare commits
121 Commits
0.8.7
...
prodinfo_b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
967f14fc7e | ||
|
|
3bba035b84 | ||
|
|
bb6cc6532b | ||
|
|
03a425a579 | ||
|
|
41f5b39f6b | ||
|
|
b5dd621250 | ||
|
|
27cde7da7a | ||
|
|
377b8dae9f | ||
|
|
78828427a4 | ||
|
|
fe28dac9d3 | ||
|
|
a85102c97c | ||
|
|
9b11f1cb19 | ||
|
|
cf6b9de370 | ||
|
|
80c380e61e | ||
|
|
967fa456ba | ||
|
|
6ae6c80c25 | ||
|
|
142df74694 | ||
|
|
00db1dc286 | ||
|
|
1456246f60 | ||
|
|
7581306109 | ||
|
|
a4ee4d20ad | ||
|
|
625ac5b357 | ||
|
|
3f75a92fd2 | ||
|
|
b5e91ff9a4 | ||
|
|
db47a0c041 | ||
|
|
5e7b33cabd | ||
|
|
3cc79f4e11 | ||
|
|
7c36a827da | ||
|
|
ea90325535 | ||
|
|
72377c2345 | ||
|
|
cccef3b85c | ||
|
|
e10c6a3217 | ||
|
|
4ef7b83e34 | ||
|
|
4ca53e2ef1 | ||
|
|
d9da531b41 | ||
|
|
93fb060fac | ||
|
|
fe0d41623c | ||
|
|
4ea6ce3156 | ||
|
|
520b5f6c59 | ||
|
|
505324f625 | ||
|
|
9319463a6e | ||
|
|
31c4c33042 | ||
|
|
55a8154691 | ||
|
|
453c05cf7c | ||
|
|
4c5c78858c | ||
|
|
967613a261 | ||
|
|
348345340d | ||
|
|
38159bdf9a | ||
|
|
e58948a42b | ||
|
|
9c53c0c0cc | ||
|
|
7c5dc61795 | ||
|
|
6034beb084 | ||
|
|
8c3dae846e | ||
|
|
dcc93ce60e | ||
|
|
7fef83885f | ||
|
|
3207c38a44 | ||
|
|
5952ebab54 | ||
|
|
ad41d010d3 | ||
|
|
21db90bae9 | ||
|
|
cf4f74c8f9 | ||
|
|
bf5a649928 | ||
|
|
c5fa4660c8 | ||
|
|
0d4a0348b5 | ||
|
|
51858e732a | ||
|
|
edcfbf4254 | ||
|
|
d984621150 | ||
|
|
4b8ebfa7c3 | ||
|
|
bc44e02aed | ||
|
|
85e8506fa8 | ||
|
|
5633444d5e | ||
|
|
99106076e6 | ||
|
|
0a194cb6a6 | ||
|
|
f4a8124dc3 | ||
|
|
9ea1a2a941 | ||
|
|
bfa84e27c1 | ||
|
|
14683405be | ||
|
|
ccbab35deb | ||
|
|
2dfa1c96d1 | ||
|
|
d44b91826d | ||
|
|
3a8f9114fc | ||
|
|
9858d6fc95 | ||
|
|
f6645387b0 | ||
|
|
df963967f5 | ||
|
|
8313669716 | ||
|
|
13c825a8bb | ||
|
|
30485f1df9 | ||
|
|
7945a921ca | ||
|
|
b09adb6a34 | ||
|
|
c3875796df | ||
|
|
a1d4caa7b4 | ||
|
|
9f972831cc | ||
|
|
f50bfaf7d7 | ||
|
|
bfd04cfe92 | ||
|
|
cb74bc6bb8 | ||
|
|
be4ca7eee5 | ||
|
|
7b24b43477 | ||
|
|
253afc90a4 | ||
|
|
a09c08994f | ||
|
|
13ded6bd1c | ||
|
|
4ba6d8b24c | ||
|
|
cb88fdfd62 | ||
|
|
d69fc060f4 | ||
|
|
e04fcfff6b | ||
|
|
79c52e2b91 | ||
|
|
4ac8f2745b | ||
|
|
6004b7479e | ||
|
|
ed86c44a49 | ||
|
|
5c9d0f05b1 | ||
|
|
87f7a6ebdc | ||
|
|
664e5e6b52 | ||
|
|
9691286d73 | ||
|
|
81895c8019 | ||
|
|
1a396235cd | ||
|
|
732a6159f7 | ||
|
|
a3389e25c9 | ||
|
|
908de31a0e | ||
|
|
4e5f033e41 | ||
|
|
ae90a9d7a6 | ||
|
|
a67d4064f0 | ||
|
|
d0659377e8 | ||
|
|
ac07971211 |
21
Makefile
21
Makefile
@@ -50,11 +50,13 @@ dist: all
|
||||
mkdir atmosphere-$(AMSVER)/atmosphere
|
||||
mkdir atmosphere-$(AMSVER)/sept
|
||||
mkdir atmosphere-$(AMSVER)/switch
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
|
||||
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
|
||||
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
|
||||
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
|
||||
@@ -65,13 +67,16 @@ dist: all
|
||||
cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini
|
||||
cp -r common/defaults/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
|
||||
cp -r common/defaults/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
|
||||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
|
||||
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp
|
||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D/exefs.nsp
|
||||
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp
|
||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
||||
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp
|
||||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
|
||||
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/exefs.nsp
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
|
||||
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag
|
||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D/exefs.nsp
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/flags
|
||||
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/flags/boot2.flag
|
||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
||||
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
||||
rm -r atmosphere-$(AMSVER)
|
||||
mkdir out
|
||||
|
||||
@@ -8,6 +8,9 @@ stage2_entrypoint = 0xF0000000
|
||||
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
|
||||
debugmode = 1
|
||||
debugmode_user = 0
|
||||
; Note: Disabling usermode exception handlers will cause atmosphere to not fail gracefully under error conditions.
|
||||
; Support will not be provided to users who disable these. If you do not know what you are doing, leave them on.
|
||||
disable_user_exception_handlers = 0
|
||||
|
||||
[stratosphere]
|
||||
; To force-enable nogc, add nogc = 1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -4,8 +4,15 @@ upload_enabled = u8!0x0
|
||||
; Enable USB 3.0 superspeed for homebrew
|
||||
[usb]
|
||||
usb30_force_enabled = u8!0x0
|
||||
; Control whether RO should ease its validation of NROs.
|
||||
; (note: this is normally not necessary, and ips patches can be used.)
|
||||
[ro]
|
||||
ease_nro_restriction = u8!0x0
|
||||
; Atmosphere custom settings
|
||||
[atmosphere]
|
||||
; Reboot from fatal automatically after some number of milliseconds.
|
||||
; If field is not present or 0, fatal will wait indefinitely for user input.
|
||||
fatal_auto_reboot_interval = u64!0x0
|
||||
; Make the power menu's "reboot" button reboot to payload.
|
||||
; Set to "normal" for normal reboot, "rcm" for rcm reboot.
|
||||
power_menu_reboot_function = str!payload
|
||||
|
||||
@@ -25,11 +25,12 @@
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_600 6
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_700
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_700
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
|
||||
|
||||
/* TODO: What should this be, for release? */
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 8
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 7
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 9
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 7
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1
|
||||
|
||||
|
||||
@@ -1,4 +1,36 @@
|
||||
# Changelog
|
||||
## 0.8.9
|
||||
+ A number of bugs were fixed, including:
|
||||
+ A data abort was fixed when mounting certain partitions on NAND.
|
||||
+ All Stratosphère system modules now only maintain a connection to `sm` when actively using it.
|
||||
+ This helps mitigate the scenario where sm hits the limit of 64 active connections and crashes.
|
||||
+ This sometimes caused crashes when custom non-Atmosphère sysmodules were active and the user played certain games (ex: Smash's Stage Builder).
|
||||
+ fatal now uses the 8.0.0 clkrst API, instead of silently failing to adjust clock rates on that firmware version.
|
||||
+ A wait loop is now performed when trying to get a session to `sm`, in the case where `sm:` is not yet registered.
|
||||
+ This fixes a race condition that could cause a failure to boot under certain circumstances.
|
||||
+ libstratosphere's handling of domain object closing has been improved.
|
||||
+ Previously, this code could cause crashes/extremely odd behavior (misinterpreting what object a service is) under certain circumstances.
|
||||
+ An optional automatic reboot timer was added to fatal.
|
||||
+ By setting the system setting `atmosphere!fatal_auto_reboot_interval` to a non-zero u64 value, fatal can be made to automatically reboot after a certain number of milliseconds.
|
||||
+ If the setting is zero or not present, fatal will wait for user input as usual.
|
||||
+ Atmosphère now provides a reimplementation of the `ro` system module.
|
||||
+ `ro` is responsible for loading dynamic libraries (NROs) on 3.0.0+.
|
||||
+ On 1.0.0-2.3.0, this is handled by `loader`.
|
||||
+ Atmosphere's `ro` provides this functionality (`ldr:ro`, `ro:dmnt`) on all firmware versions.
|
||||
+ An extension was implemented to provide support for applying IPS patches to NROs.
|
||||
+ All patches at paths like /atmosphere/nro_patches/<user-defined patch name>/<Hex Build-ID for NRO to patch>.ips will be applied, allowing for easy distribution of patches.
|
||||
+ Both the IPS and IPS32 formats are supported.
|
||||
+ Atmosphère now provides a reimplementation of the `spl` system module.
|
||||
+ `spl` (Secure Platform Services) is responsible for cryptographic operations, including all communications with the secure monitor (exosphère).
|
||||
+ In the future, this may be used to provide extensions to the API for interacting with exosphère from userland.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.8.8
|
||||
+ Support was added for firmware version 8.0.0.
|
||||
+ Custom exception handlers were added to stratosphere modules.
|
||||
+ If a crash happens in a core atmosphere module now, instead of silently failing a reboot will occur to log the information to the SD card.
|
||||
+ A bug was fixed in creport that caused games to hang when crashing under certain circumstances.
|
||||
+ A bug was fixed that prevented maintenance mode from booting on 7.0.0+.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.8.7
|
||||
+ A few bugs were fixed that could cause fatal to fail to show an error under certain circumstances.
|
||||
+ A bug was fixed that caused an error when launching certain games (e.g. Hellblade: Senua's Sacrifice).
|
||||
|
||||
@@ -100,6 +100,8 @@ uint64_t bootconfig_get_value_for_sysctr0(void) {
|
||||
}
|
||||
|
||||
uint64_t bootconfig_get_memory_arrangement(void) {
|
||||
/* TODO: This function has changed pretty significantly since we implemented it. */
|
||||
/* Not relevant for retail, but we'll probably want this to be accurate sooner or later. */
|
||||
if (bootconfig_is_debug_mode()) {
|
||||
if (fuse_get_dram_id() == 4) {
|
||||
if (LOADED_BOOTCONFIG->unsigned_config.data[0x23]) {
|
||||
|
||||
@@ -35,13 +35,14 @@
|
||||
#undef u8
|
||||
#undef u32
|
||||
|
||||
static bool g_battery_profile = false;
|
||||
static bool g_hiz_mode_enabled = false;
|
||||
static bool g_debugmode_override_user = false, g_debugmode_override_priv = false;
|
||||
static bool g_enable_usermode_exception_handlers = true;
|
||||
|
||||
uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) {
|
||||
switch (item) {
|
||||
case CONFIGITEM_BATTERYPROFILE:
|
||||
g_battery_profile = (value != 0);
|
||||
case CONFIGITEM_HIZMODE:
|
||||
g_hiz_mode_enabled = (value != 0);
|
||||
break;
|
||||
case CONFIGITEM_NEEDS_REBOOT:
|
||||
/* Force a reboot, if requested. */
|
||||
@@ -133,8 +134,12 @@ bool configitem_is_retail(void) {
|
||||
return is_retail != 0;
|
||||
}
|
||||
|
||||
bool configitem_should_profile_battery(void) {
|
||||
return g_battery_profile;
|
||||
bool configitem_is_hiz_mode_enabled(void) {
|
||||
return g_hiz_mode_enabled;
|
||||
}
|
||||
|
||||
void configitem_set_hiz_mode_enabled(bool enabled) {
|
||||
g_hiz_mode_enabled = enabled;
|
||||
}
|
||||
|
||||
bool configitem_is_debugmode_priv(void) {
|
||||
@@ -159,6 +164,10 @@ void configitem_set_debugmode_override(bool user, bool priv) {
|
||||
g_debugmode_override_priv = priv;
|
||||
}
|
||||
|
||||
void configitem_disable_usermode_exception_handlers(void) {
|
||||
g_enable_usermode_exception_handlers = false;
|
||||
}
|
||||
|
||||
uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) {
|
||||
uint32_t result = 0;
|
||||
switch (item) {
|
||||
@@ -209,13 +218,15 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
|
||||
case CONFIGITEM_KERNELCONFIGURATION:
|
||||
{
|
||||
uint64_t config = bootconfig_get_kernel_configuration();
|
||||
/* Always enable usermode exception handlers. */
|
||||
config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS;
|
||||
/* Enable usermode exception handlers by default. */
|
||||
if (g_enable_usermode_exception_handlers) {
|
||||
config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS;
|
||||
}
|
||||
*p_outvalue = config;
|
||||
}
|
||||
break;
|
||||
case CONFIGITEM_BATTERYPROFILE:
|
||||
*p_outvalue = (int)g_battery_profile;
|
||||
case CONFIGITEM_HIZMODE:
|
||||
*p_outvalue = (int)g_hiz_mode_enabled;
|
||||
break;
|
||||
case CONFIGITEM_ISQUESTUNIT:
|
||||
/* Added on 3.0, used to determine whether console is a kiosk unit. */
|
||||
@@ -271,7 +282,11 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
|
||||
break;
|
||||
case CONFIGITEM_HAS_RCM_BUG_PATCH:
|
||||
/* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */
|
||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());;
|
||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());
|
||||
break;
|
||||
case CONFIGITEM_SHOULD_BLANK_PROD_INFO:
|
||||
/* UNOFFICIAL: Gets whether we should blank out certain parts of PRODINFO. */
|
||||
*p_outvalue = (int)(exosphere_should_blank_prod_info() != 0);
|
||||
break;
|
||||
default:
|
||||
result = 2;
|
||||
|
||||
@@ -33,7 +33,7 @@ typedef enum {
|
||||
CONFIGITEM_MEMORYARRANGE = 10,
|
||||
CONFIGITEM_ISDEBUGMODE = 11,
|
||||
CONFIGITEM_KERNELCONFIGURATION = 12,
|
||||
CONFIGITEM_BATTERYPROFILE = 13,
|
||||
CONFIGITEM_HIZMODE = 13,
|
||||
CONFIGITEM_ISQUESTUNIT = 14,
|
||||
CONFIGITEM_NEWHARDWARETYPE_5X = 15,
|
||||
CONFIGITEM_NEWKEYGENERATION_5X = 16,
|
||||
@@ -45,6 +45,7 @@ typedef enum {
|
||||
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
|
||||
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
|
||||
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
|
||||
CONFIGITEM_SHOULD_BLANK_PROD_INFO = 65005,
|
||||
} ConfigItem;
|
||||
|
||||
#define REBOOT_KIND_NO_REBOOT 0
|
||||
@@ -56,10 +57,12 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue);
|
||||
|
||||
bool configitem_is_recovery_boot(void);
|
||||
bool configitem_is_retail(void);
|
||||
bool configitem_should_profile_battery(void);
|
||||
bool configitem_is_hiz_mode_enabled(void);
|
||||
bool configitem_is_debugmode_priv(void);
|
||||
|
||||
void configitem_set_debugmode_override(bool user, bool priv);
|
||||
void configitem_disable_usermode_exception_handlers(void);
|
||||
void configitem_set_hiz_mode_enabled(bool enabled);
|
||||
|
||||
uint64_t configitem_get_hardware_type(void);
|
||||
|
||||
|
||||
@@ -75,3 +75,19 @@ unsigned int exosphere_should_override_debugmode_user(void) {
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
||||
}
|
||||
|
||||
unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||
}
|
||||
|
||||
unsigned int exosphere_should_blank_prod_info(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,12 @@
|
||||
/* Exosphere config in DRAM shares physical/virtual mapping. */
|
||||
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
|
||||
|
||||
#define EXOSPHERE_FLAGS_DEFAULT 0x00000000
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#define EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO (1 << 4u)
|
||||
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
|
||||
|
||||
typedef struct {
|
||||
unsigned int magic;
|
||||
@@ -52,6 +54,8 @@ unsigned int exosphere_get_target_firmware(void);
|
||||
unsigned int exosphere_should_perform_620_keygen(void);
|
||||
unsigned int exosphere_should_override_debugmode_priv(void);
|
||||
unsigned int exosphere_should_override_debugmode_user(void);
|
||||
unsigned int exosphere_should_disable_usermode_exception_handlers(void);
|
||||
unsigned int exosphere_should_blank_prod_info(void);
|
||||
|
||||
static inline unsigned int exosphere_get_target_firmware_for_init(void) {
|
||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;
|
||||
|
||||
@@ -140,13 +140,19 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
|
||||
carveout->size_big_pages = (uint32_t)(size >> 17);
|
||||
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
|
||||
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW) | BIT(CSR_TSECSRD) | BIT(CSW_TSECSWR));
|
||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
|
||||
} else {
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW) | BIT(CSR_TSECSRD) | BIT(CSW_TSECSWR));
|
||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
|
||||
}
|
||||
carveout->client_force_internal_access_0 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) && (carveout_id == 4)) ? BIT(CSR_AVPCARM7R) : 0;
|
||||
carveout->client_force_internal_access_1 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) && (carveout_id == 4)) ? BIT(CSW_AVPCARM7W) : 0;
|
||||
carveout->client_force_internal_access_2 = 0;
|
||||
carveout->client_force_internal_access_3 = 0;
|
||||
carveout->client_force_internal_access_4 = 0;
|
||||
carveout->config = 0x8B;
|
||||
carveout->config = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) ? 0x4CB : 0x8B;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ static void setup_se(void) {
|
||||
master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
|
||||
break;
|
||||
default:
|
||||
@@ -179,6 +180,7 @@ static void setup_se(void) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_600:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
||||
break;
|
||||
}
|
||||
@@ -334,10 +336,15 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||
}
|
||||
|
||||
/* Ensure no overlap with later sections. */
|
||||
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
|
||||
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
|
||||
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
|
||||
return false;
|
||||
if (metadata->section_sizes[section] != 0) {
|
||||
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
|
||||
if (metadata->section_sizes[later_section] == 0) {
|
||||
continue;
|
||||
}
|
||||
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
|
||||
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +397,7 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
||||
}
|
||||
|
||||
/* Ensure we successfully decrypted the header. */
|
||||
if (mkey_rev > mkey_get_revision()) {
|
||||
if (mkey_rev > mkey_get_revision()) {
|
||||
panic(0xFAF00003);
|
||||
}
|
||||
} else if (!validate_package2_metadata(&header->metadata)) {
|
||||
@@ -487,6 +494,7 @@ static void copy_warmboot_bin_to_dram() {
|
||||
warmboot_src = (uint8_t *)0x4003D800;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
warmboot_src = (uint8_t *)0x4003E000;
|
||||
break;
|
||||
}
|
||||
@@ -530,6 +538,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
/* Load Exosphere-specific config. */
|
||||
exosphere_load_config();
|
||||
configitem_set_debugmode_override(exosphere_should_override_debugmode_user() != 0, exosphere_should_override_debugmode_priv() != 0);
|
||||
if (exosphere_should_disable_usermode_exception_handlers() != 0) {
|
||||
configitem_disable_usermode_exception_handlers();
|
||||
}
|
||||
|
||||
/* Setup the Security Engine. */
|
||||
setup_se();
|
||||
@@ -554,6 +565,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0xA8;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -44,11 +44,11 @@
|
||||
#undef u8
|
||||
#undef u32
|
||||
|
||||
static void configure_battery_hi_z_mode(void) {
|
||||
static void configure_battery_hiz_mode(void) {
|
||||
clkrst_reboot(CARDEVICE_I2C1);
|
||||
|
||||
if (configitem_should_profile_battery() && !i2c_query_ti_charger_bit_7()) {
|
||||
/* Profile the battery. */
|
||||
if (configitem_is_hiz_mode_enabled() && !i2c_query_ti_charger_bit_7()) {
|
||||
/* Configure HiZ mode. */
|
||||
i2c_set_ti_charger_bit_7();
|
||||
uint32_t start_time = get_time();
|
||||
bool should_wait = true;
|
||||
@@ -109,7 +109,7 @@ static void mitigate_jamais_vu(void) {
|
||||
}
|
||||
|
||||
/* Jamais Vu mitigation #3: Ensure all relevant DMA controllers are held in reset. */
|
||||
if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000004) != 0x4000004) {
|
||||
if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000006) != 0x4000006) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
|
||||
}
|
||||
|
||||
/* Perform I2C comms with TI charger if required. */
|
||||
configure_battery_hi_z_mode();
|
||||
configure_battery_hiz_mode();
|
||||
|
||||
/* Enable LP0 Wake Event Detection. */
|
||||
enable_lp0_wake_events();
|
||||
|
||||
@@ -38,11 +38,6 @@
|
||||
#include "sc7.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#define SMC_USER_HANDLERS 0x13
|
||||
#define SMC_PRIV_HANDLERS 0x9
|
||||
|
||||
#define SMC_AMS_HANDLERS 0x2
|
||||
|
||||
#define DEBUG_LOG_SMCS 0
|
||||
#define DEBUG_PANIC_ON_FAILURE 0
|
||||
|
||||
@@ -83,8 +78,12 @@ uint32_t smc_read_write_register(smc_args_t *args);
|
||||
/* Atmosphere SMC prototypes */
|
||||
uint32_t smc_ams_iram_copy(smc_args_t *args);
|
||||
|
||||
/* TODO: Provide a way to set this. It's 0 on non-recovery boot anyway... */
|
||||
static uint32_t g_smc_blacklist_mask = 0;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint32_t blacklist_mask;
|
||||
uint32_t (*handler)(smc_args_t *args);
|
||||
} smc_table_entry_t;
|
||||
|
||||
@@ -93,45 +92,49 @@ typedef struct {
|
||||
uint32_t num_handlers;
|
||||
} smc_table_t;
|
||||
|
||||
static smc_table_entry_t g_smc_user_table[SMC_USER_HANDLERS] = {
|
||||
{0, NULL},
|
||||
{0xC3000401, smc_set_config_user},
|
||||
{0xC3000002, smc_get_config_user},
|
||||
{0xC3000003, smc_check_status},
|
||||
{0xC3000404, smc_get_result},
|
||||
{0xC3000E05, smc_exp_mod},
|
||||
{0xC3000006, smc_get_random_bytes_for_user},
|
||||
{0xC3000007, smc_generate_aes_kek},
|
||||
{0xC3000008, smc_load_aes_key},
|
||||
{0xC3000009, smc_crypt_aes},
|
||||
{0xC300000A, smc_generate_specific_aes_key},
|
||||
{0xC300040B, smc_compute_cmac},
|
||||
{0xC300100C, smc_load_rsa_oaep_key},
|
||||
{0xC300100D, smc_decrypt_rsa_private_key},
|
||||
{0xC300100E, smc_load_secure_exp_mod_key},
|
||||
{0xC300060F, smc_secure_exp_mod},
|
||||
{0xC3000610, smc_unwrap_rsa_oaep_wrapped_titlekey},
|
||||
{0xC3000011, smc_load_titlekey},
|
||||
{0xC3000012, smc_unwrap_aes_wrapped_titlekey}
|
||||
static smc_table_entry_t g_smc_user_table[] = {
|
||||
{0, 4, NULL},
|
||||
{0xC3000401, 4, smc_set_config_user},
|
||||
{0xC3000002, 1, smc_get_config_user},
|
||||
{0xC3000003, 1, smc_check_status},
|
||||
{0xC3000404, 1, smc_get_result},
|
||||
{0xC3000E05, 4, smc_exp_mod},
|
||||
{0xC3000006, 1, smc_get_random_bytes_for_user},
|
||||
{0xC3000007, 1, smc_generate_aes_kek},
|
||||
{0xC3000008, 1, smc_load_aes_key},
|
||||
{0xC3000009, 1, smc_crypt_aes},
|
||||
{0xC300000A, 1, smc_generate_specific_aes_key},
|
||||
{0xC300040B, 1, smc_compute_cmac},
|
||||
{0xC300100C, 1, smc_load_rsa_oaep_key},
|
||||
{0xC300100D, 2, smc_decrypt_rsa_private_key},
|
||||
{0xC300100E, 4, smc_load_secure_exp_mod_key},
|
||||
{0xC300060F, 2, smc_secure_exp_mod},
|
||||
{0xC3000610, 4, smc_unwrap_rsa_oaep_wrapped_titlekey},
|
||||
{0xC3000011, 4, smc_load_titlekey},
|
||||
{0xC3000012, 4, smc_unwrap_aes_wrapped_titlekey}
|
||||
};
|
||||
#define SMC_USER_HANDLERS (sizeof(g_smc_user_table) / sizeof(g_smc_user_table[0]))
|
||||
|
||||
static smc_table_entry_t g_smc_priv_table[SMC_PRIV_HANDLERS] = {
|
||||
{0, NULL},
|
||||
{0xC4000001, smc_cpu_suspend},
|
||||
{0x84000002, smc_cpu_off},
|
||||
{0xC4000003, smc_cpu_on},
|
||||
{0xC3000004, smc_get_config_priv},
|
||||
{0xC3000005, smc_get_random_bytes_for_priv},
|
||||
{0xC3000006, smc_panic},
|
||||
{0xC3000007, smc_configure_carveout},
|
||||
{0xC3000008, smc_read_write_register}
|
||||
static smc_table_entry_t g_smc_priv_table[] = {
|
||||
{0, 4, NULL},
|
||||
{0xC4000001, 4, smc_cpu_suspend},
|
||||
{0x84000002, 4, smc_cpu_off},
|
||||
{0xC4000003, 1, smc_cpu_on},
|
||||
{0xC3000004, 1, smc_get_config_priv},
|
||||
{0xC3000005, 1, smc_get_random_bytes_for_priv},
|
||||
{0xC3000006, 1, smc_panic},
|
||||
{0xC3000007, 1, smc_configure_carveout},
|
||||
{0xC3000008, 1, smc_read_write_register}
|
||||
};
|
||||
#define SMC_PRIV_HANDLERS (sizeof(g_smc_priv_table) / sizeof(g_smc_priv_table[0]))
|
||||
|
||||
/* This is a table used for atmosphere-specific SMCs. */
|
||||
static smc_table_entry_t g_smc_ams_table[SMC_AMS_HANDLERS] = {
|
||||
{0, NULL},
|
||||
{0xF0000201, smc_ams_iram_copy},
|
||||
static smc_table_entry_t g_smc_ams_table[] = {
|
||||
{0, 4, NULL},
|
||||
{0xF0000201, 0, smc_ams_iram_copy},
|
||||
{0xF0000002, 0, smc_read_write_register},
|
||||
};
|
||||
#define SMC_AMS_HANDLERS (sizeof(g_smc_ams_table) / sizeof(g_smc_ams_table[0]))
|
||||
|
||||
static smc_table_t g_smc_tables[SMC_HANDLER_COUNT + 1] = {
|
||||
{ /* SMC_HANDLER_USER */
|
||||
@@ -177,6 +180,7 @@ void set_version_specific_smcs(void) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_600:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
/* No more LoadSecureExpModKey. */
|
||||
g_smc_user_table[0xE].handler = NULL;
|
||||
g_smc_user_table[0xC].id = 0xC300D60C;
|
||||
@@ -292,13 +296,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
|
||||
#endif
|
||||
|
||||
/* Call function. */
|
||||
args->X[0] = smc_handler(args);
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 ||
|
||||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
|
||||
args->X[0] = smc_handler(args);
|
||||
} else {
|
||||
/* Call not allowed due to current boot conditions. */
|
||||
args->X[0] = 6;
|
||||
}
|
||||
|
||||
#if DEBUG_LOG_SMCS
|
||||
if (handler_id == SMC_HANDLER_USER) {
|
||||
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args;
|
||||
/*if (num >= 0x69) {
|
||||
panic(PANIC_REBOOT);
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_600:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
default:
|
||||
return keyslot <= 5;
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
|
||||
SAVE_SYSREG64(ELR_EL3, 0x18);
|
||||
SAVE_SYSREG64(FAR_EL3, 0x20);
|
||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x2;
|
||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
|
||||
*/
|
||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10; */
|
||||
|
||||
|
||||
/* TODO: Custom Panic Driver, which displays to screen without rebooting. */
|
||||
/* For now, just use NX BOOTLOADER's panic. */
|
||||
@@ -68,9 +68,9 @@ __attribute__ ((noreturn)) void panic_predefined(uint32_t which) {
|
||||
|
||||
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
||||
{
|
||||
if(as <= bs && bs <= ae)
|
||||
if(as <= bs && bs < ae)
|
||||
return true;
|
||||
if(bs <= as && as <= be)
|
||||
if(bs <= as && as < be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ void init_dma_controllers(unsigned int target_firmware) {
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
|
||||
/* AHB_ARBITRATION_DISABLE_0 - Disables USB and USB2 from arbitration */
|
||||
MAKE_REG32(0x6000C004) = 0x40040;
|
||||
/* AHB_ARBITRATION_DISABLE_0 - Disables USB, USB2, and AHB-DMA from arbitration */
|
||||
MAKE_REG32(0x6000C004) = 0x40060;
|
||||
|
||||
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
|
||||
MAKE_REG32(0x6000C008) = 0xE0000001;
|
||||
|
||||
@@ -39,6 +39,17 @@ uintptr_t get_warmboot_main_stack_address(void) {
|
||||
return TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x780;
|
||||
}
|
||||
|
||||
static void warmboot_configure_hiz_mode(void) {
|
||||
/* Enable input to I2C1 */
|
||||
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
|
||||
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
|
||||
|
||||
clkrst_reboot(CARDEVICE_I2C1);
|
||||
i2c_init(0);
|
||||
i2c_clear_ti_charger_bit_7();
|
||||
clkrst_disable(CARDEVICE_I2C1);
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) warmboot_main(void) {
|
||||
/*
|
||||
This function and its callers are reached in either of the following events, under normal conditions:
|
||||
@@ -79,15 +90,10 @@ void __attribute__((noreturn)) warmboot_main(void) {
|
||||
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
|
||||
secure_additional_devices();
|
||||
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400 || configitem_get_hardware_type() == 0) {
|
||||
/* Enable input to I2C1 */
|
||||
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
|
||||
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
|
||||
|
||||
clkrst_reboot(CARDEVICE_I2C1);
|
||||
i2c_init(0);
|
||||
i2c_clear_ti_charger_bit_7();
|
||||
clkrst_disable(CARDEVICE_I2C1);
|
||||
if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) ||
|
||||
((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800) && configitem_get_hardware_type() == 0) ||
|
||||
(configitem_is_hiz_mode_enabled())) {
|
||||
warmboot_configure_hiz_mode();
|
||||
}
|
||||
|
||||
clear_user_smc_in_progress();
|
||||
|
||||
@@ -90,9 +90,6 @@ static void setup_env(void) {
|
||||
/* Initialize hardware. */
|
||||
nx_hwinit();
|
||||
|
||||
/* Check for panics. */
|
||||
check_and_display_panic();
|
||||
|
||||
/* Zero-fill the framebuffer and register it as printk provider. */
|
||||
video_init(g_framebuffer);
|
||||
|
||||
@@ -138,6 +135,9 @@ int main(void) {
|
||||
|
||||
/* Initialize the display, console, etc. */
|
||||
setup_env();
|
||||
|
||||
/* Check for panics. */
|
||||
check_and_display_panic();
|
||||
|
||||
/* Load the BCT0 configuration ini off of the SD. */
|
||||
bct0 = load_config();
|
||||
|
||||
@@ -14,15 +14,78 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "panic.h"
|
||||
#include "di.h"
|
||||
#include "pmc.h"
|
||||
#include "fuse.h"
|
||||
#include "utils.h"
|
||||
#include "fs_utils.h"
|
||||
#include "lib/log.h"
|
||||
|
||||
static uint32_t g_panic_code = 0;
|
||||
|
||||
static const char *get_error_desc_str(uint32_t error_desc) {
|
||||
switch (error_desc) {
|
||||
case 0x100:
|
||||
return "Instruction Abort";
|
||||
case 0x101:
|
||||
return "Data Abort";
|
||||
case 0x102:
|
||||
return "PC Misalignment";
|
||||
case 0x103:
|
||||
return "SP Misalignment";
|
||||
case 0x104:
|
||||
return "Trap";
|
||||
case 0x106:
|
||||
return "SError";
|
||||
case 0x301:
|
||||
return "Bad SVC";
|
||||
case 0xFFE:
|
||||
return "std::abort() called";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void _check_and_display_atmosphere_fatal_error(void) {
|
||||
/* Check for valid magic. */
|
||||
if (ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC &&
|
||||
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
/* Copy fatal error context to the stack. */
|
||||
atmosphere_fatal_error_ctx ctx = *(ATMOSPHERE_FATAL_ERROR_CONTEXT);
|
||||
|
||||
/* Change magic to invalid, to prevent double-display of error/bootlooping. */
|
||||
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic = 0xCCCCCCCC;
|
||||
|
||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "A fatal error occurred when running Atmosph\xe8re.\n");
|
||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Title ID: %016llx\n", ctx.title_id);
|
||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Error Desc: %s (0x%x)\n", get_error_desc_str(ctx.error_desc), ctx.error_desc);
|
||||
|
||||
/* Save context to the SD card. */
|
||||
{
|
||||
char filepath[0x40];
|
||||
snprintf(filepath, sizeof(filepath) - 1, "/atmosphere/fatal_errors/report_%016llx.bin", ctx.report_identifier);
|
||||
filepath[sizeof(filepath)-1] = 0;
|
||||
write_to_file(&ctx, sizeof(ctx), filepath);
|
||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"Report saved to %s\n", filepath);
|
||||
}
|
||||
|
||||
/* Display error. */
|
||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
|
||||
}
|
||||
|
||||
wait_for_button_and_reboot();
|
||||
}
|
||||
|
||||
void check_and_display_panic(void) {
|
||||
/* Handle a panic sent via a stratosphere module. */
|
||||
_check_and_display_atmosphere_fatal_error();
|
||||
|
||||
/* We also handle our own panics. */
|
||||
/* In the case of our own panics, we assume that the display has already been initialized. */
|
||||
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;
|
||||
|
||||
@@ -28,6 +28,45 @@
|
||||
|
||||
#define PANIC_CODE_SAFEMODE 0x00000020
|
||||
|
||||
|
||||
#define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20
|
||||
#define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100
|
||||
|
||||
/* Atmosphere reboot-to-fatal-error. */
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t error_desc;
|
||||
uint64_t title_id;
|
||||
union {
|
||||
uint64_t gprs[32];
|
||||
struct {
|
||||
uint64_t _gprs[29];
|
||||
uint64_t fp;
|
||||
uint64_t lr;
|
||||
uint64_t sp;
|
||||
};
|
||||
};
|
||||
uint64_t pc;
|
||||
uint64_t module_base;
|
||||
uint32_t pstate;
|
||||
uint32_t afsr0;
|
||||
uint32_t afsr1;
|
||||
uint32_t esr;
|
||||
uint64_t far;
|
||||
uint64_t report_identifier; /* Normally just system tick. */
|
||||
uint64_t stack_trace_size;
|
||||
uint64_t stack_dump_size;
|
||||
uint64_t stack_trace[AMS_FATAL_ERROR_MAX_STACKTRACE];
|
||||
uint8_t stack_dump[AMS_FATAL_ERROR_MAX_STACKDUMP];
|
||||
} atmosphere_fatal_error_ctx;
|
||||
|
||||
/* "AFE1" */
|
||||
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x31454641
|
||||
/* "AFE0" */
|
||||
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0 0x30454641
|
||||
|
||||
#define ATMOSPHERE_FATAL_ERROR_CONTEXT ((volatile atmosphere_fatal_error_ctx *)(0x4003E000))
|
||||
|
||||
void check_and_display_panic(void);
|
||||
__attribute__ ((noreturn)) void panic(uint32_t code);
|
||||
|
||||
|
||||
@@ -1202,6 +1202,9 @@ void sdmmc_finish(sdmmc_t *sdmmc)
|
||||
|
||||
/* Power cycle for 100ms without power. */
|
||||
mdelay(100);
|
||||
|
||||
/* Disable the regulator. */
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
}
|
||||
|
||||
/* Force a register read to refresh the clock control value. */
|
||||
|
||||
@@ -84,7 +84,7 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot $(AMS)/stratosphere/ams_mitm
|
||||
export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot $(AMS)/stratosphere/spl $(AMS)/stratosphere/ams_mitm
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(AMS)/exosphere $(AMS)/exosphere/lp0fw $(AMS)/exosphere/rebootstub \
|
||||
@@ -96,7 +96,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip boot_100.kip boot_200.kip
|
||||
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
|
||||
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
|
||||
sept-primary.bin sept-secondary.enc \
|
||||
|
||||
@@ -220,10 +220,8 @@ SECTIONS
|
||||
======================= */
|
||||
PROVIDE(__ams_mitm_kip_start__ = ams_mitm_kip - __start__);
|
||||
PROVIDE(__ams_mitm_kip_size__ = ams_mitm_kip_end - ams_mitm_kip);
|
||||
PROVIDE(__boot_100_kip_start__ = boot_100_kip - __start__);
|
||||
PROVIDE(__boot_100_kip_size__ = boot_100_kip_end - boot_100_kip);
|
||||
PROVIDE(__boot_200_kip_start__ = boot_200_kip - __start__);
|
||||
PROVIDE(__boot_200_kip_size__ = boot_200_kip_end - boot_200_kip);
|
||||
PROVIDE(__boot_kip_start__ = boot_kip - __start__);
|
||||
PROVIDE(__boot_kip_size__ = boot_kip_end - boot_kip);
|
||||
PROVIDE(__exosphere_bin_start__ = exosphere_bin - __start__);
|
||||
PROVIDE(__exosphere_bin_size__ = exosphere_bin_end - exosphere_bin);
|
||||
PROVIDE(__fusee_primary_bin_start__ = fusee_primary_bin - __start__);
|
||||
@@ -242,6 +240,8 @@ SECTIONS
|
||||
PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
|
||||
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
|
||||
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
|
||||
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
|
||||
PROVIDE(__spl_kip_size__ = spl_kip_end - spl_kip);
|
||||
PROVIDE(__splash_screen_bmp_start__ = splash_screen_bmp - __start__);
|
||||
PROVIDE(__splash_screen_bmp_size__ = splash_screen_bmp_end - splash_screen_bmp);
|
||||
PROVIDE(__thermosphere_bin_start__ = thermosphere_bin - __start__);
|
||||
|
||||
@@ -24,10 +24,12 @@
|
||||
/* "EXO0" */
|
||||
#define MAGIC_EXOSPHERE_CONFIG (0x304F5845)
|
||||
|
||||
#define EXOSPHERE_FLAGS_DEFAULT 0x00000000
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#define EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO (1 << 4u)
|
||||
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
|
||||
|
||||
typedef struct {
|
||||
unsigned int magic;
|
||||
@@ -41,5 +43,6 @@ typedef struct {
|
||||
#define EXOSPHERE_TARGETFW_KEY "target_firmware"
|
||||
#define EXOSPHERE_DEBUGMODE_PRIV_KEY "debugmode"
|
||||
#define EXOSPHERE_DEBUGMODE_USER_KEY "debugmode_user"
|
||||
#define EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers"
|
||||
|
||||
#endif
|
||||
@@ -41,6 +41,10 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
uint8_t hash[0x20]; /* TODO: Come up with a better way to identify kernels, that doesn't rely on hashing them. */
|
||||
size_t hash_offset; /* Start hashing at offset N, if this is set. */
|
||||
size_t hash_size; /* Only hash the first N bytes of the kernel, if this is set. */
|
||||
size_t embedded_ini_offset; /* 8.0.0+ embeds the INI in kernel section. */
|
||||
size_t embedded_ini_ptr; /* 8.0.0+ embeds the INI in kernel section. */
|
||||
size_t free_code_space_offset;
|
||||
unsigned int num_patches;
|
||||
const kernel_patch_t *patches;
|
||||
@@ -366,11 +370,67 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(700, proc_id_send)[] = {0xA9BF
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(700, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xA9, 0x83, 0x50, 0xF8, 0xE8, 0x03, 0x16, 0x2A, 0xD6, 0x0A, 0x00, 0x11};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
|
||||
/*
|
||||
stp x10, x11, [sp, #-0x10]!
|
||||
ldr x11, [sp, #0x70]
|
||||
mov w10, w25
|
||||
lsl x10, x10, #2
|
||||
ldr x10, [x11, x10]
|
||||
mov x9, #0x0000ffffffffffff
|
||||
and x8, x10, x9
|
||||
mov x9, #0xffff000000000000
|
||||
and x10, x10, x9
|
||||
mov x9, #0xfffe000000000000
|
||||
cmp x10, x9
|
||||
beq #0x20
|
||||
|
||||
stp x8, x9, [sp, #-0x10]!
|
||||
ldr x8, [x21]
|
||||
ldr x8, [x8, #0x38]
|
||||
mov x0, x21
|
||||
blr x8
|
||||
ldp x8, x9, [sp],#0x10
|
||||
mov x8, x0
|
||||
|
||||
ldp x10, x11, [sp],#0x10
|
||||
mov x0, x8
|
||||
*/
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(800, proc_id_send)[] = {0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x15, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x03, 0x19, 0x2A, 0x39, 0x0B, 0x00, 0x11, 0x08, 0xF5, 0x7E, 0xD3};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, proc_id_send)[] = {0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
/*
|
||||
stp x10, x11, [sp, #-0x10]!
|
||||
ldr x11, [sp, #0x98]
|
||||
mov w10, w22
|
||||
lsl x10, x10, #2
|
||||
ldr x10, [x11, x10]
|
||||
mov x9, #0x0000ffffffffffff
|
||||
and x8, x10, x9
|
||||
mov x9, #0xffff000000000000
|
||||
and x10, x10, x9
|
||||
mov x9, #0xfffe000000000000
|
||||
cmp x10, x9
|
||||
beq #0x20
|
||||
|
||||
stp x8, x9, [sp, #-0x10]!
|
||||
ldr x8, [x27]
|
||||
ldr x8, [x8, #0x38]
|
||||
mov x0, x27
|
||||
blr x8
|
||||
ldp x8, x9, [sp],#0x10
|
||||
mov x8, x0
|
||||
|
||||
ldp x10, x11, [sp],#0x10
|
||||
mov x0, x8
|
||||
*/
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(800, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xA9, 0x83, 0x50, 0xF8, 0xE8, 0x03, 0x16, 0x2A, 0xD6, 0x0A, 0x00, 0x11};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
|
||||
/* svcControlCodeMemory Patches */
|
||||
/* b.eq -> nop */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
|
||||
|
||||
/* Hook Definitions. */
|
||||
static const kernel_patch_t g_kernel_patches_100[] = {
|
||||
@@ -532,6 +592,29 @@ static const kernel_patch_t g_kernel_patches_700[] = {
|
||||
.patch_offset = 0x3C6E0,
|
||||
}
|
||||
};
|
||||
static const kernel_patch_t g_kernel_patches_800[] = {
|
||||
{ /* Send Message Process ID Patch. */
|
||||
.pattern_size = 0x1C,
|
||||
.pattern = MAKE_KERNEL_PATTERN_NAME(800, proc_id_send),
|
||||
.pattern_hook_offset = 0x0,
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, proc_id_send))/sizeof(instruction_t),
|
||||
.branch_back_offset = 0x10,
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(800, proc_id_send)
|
||||
},
|
||||
{ /* Receive Message Process ID Patch. */
|
||||
.pattern_size = 0x1C,
|
||||
.pattern = MAKE_KERNEL_PATTERN_NAME(800, proc_id_recv),
|
||||
.pattern_hook_offset = 0x0,
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, proc_id_recv))/sizeof(instruction_t),
|
||||
.branch_back_offset = 0x10,
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(800, proc_id_recv)
|
||||
},
|
||||
{ /* svcControlCodeMemory Patch. */
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory))/sizeof(instruction_t),
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory),
|
||||
.patch_offset = 0x3FAD0,
|
||||
}
|
||||
};
|
||||
|
||||
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
|
||||
|
||||
@@ -581,6 +664,15 @@ static const kernel_info_t g_kernel_infos[] = {
|
||||
.hash = {0xA2, 0x5E, 0x47, 0x0C, 0x8E, 0x6D, 0x2F, 0xD7, 0x5D, 0xAD, 0x24, 0xD7, 0xD8, 0x24, 0x34, 0xFB, 0xCD, 0x77, 0xBB, 0xE6, 0x66, 0x03, 0xCB, 0xAF, 0xAB, 0x85, 0x45, 0xA0, 0x91, 0xAF, 0x34, 0x25},
|
||||
.free_code_space_offset = 0x5FEC0,
|
||||
KERNEL_PATCHES(700)
|
||||
},
|
||||
{ /* 8.0.0. */
|
||||
.hash = {0xA6, 0xAD, 0x5D, 0x7F, 0xCF, 0x25, 0x80, 0xAE, 0xE6, 0x57, 0x9F, 0x6F, 0xC5, 0xC5, 0xF6, 0x13, 0x77, 0x23, 0xAC, 0x88, 0x79, 0x76, 0xF7, 0x25, 0x06, 0x16, 0x35, 0x3B, 0x3F, 0xA7, 0x59, 0x49},
|
||||
.hash_offset = 0x1A8,
|
||||
.hash_size = 0x95000 - 0x1A8,
|
||||
.embedded_ini_offset = 0x95000,
|
||||
.embedded_ini_ptr = 0x168,
|
||||
.free_code_space_offset = 0x607F0,
|
||||
KERNEL_PATCHES(800)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -607,17 +699,27 @@ uint8_t *search_pattern(void *_mem, size_t mem_size, const void *_pattern, size_
|
||||
|
||||
const kernel_info_t *get_kernel_info(void *kernel, size_t size) {
|
||||
uint8_t calculated_hash[0x20];
|
||||
uint8_t calculated_partial_hash[0x20];
|
||||
se_calculate_sha256(calculated_hash, kernel, size);
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(g_kernel_infos)/sizeof(kernel_info_t); i++) {
|
||||
if (memcmp(calculated_hash, g_kernel_infos[i].hash, sizeof(calculated_hash)) == 0) {
|
||||
return &g_kernel_infos[i];
|
||||
if (g_kernel_infos[i].hash_size == 0 || size <= g_kernel_infos[i].hash_size) {
|
||||
if (memcmp(calculated_hash, g_kernel_infos[i].hash, sizeof(calculated_hash)) == 0) {
|
||||
return &g_kernel_infos[i];
|
||||
}
|
||||
} else {
|
||||
se_calculate_sha256(calculated_partial_hash, (void *)((uintptr_t)kernel + g_kernel_infos[i].hash_offset), g_kernel_infos[i].hash_size);
|
||||
if (memcmp(calculated_partial_hash, g_kernel_infos[i].hash, sizeof(calculated_partial_hash)) == 0) {
|
||||
return &g_kernel_infos[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel) {
|
||||
void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel, void **out_ini1) {
|
||||
const kernel_info_t *kernel_info = get_kernel_info(_kernel, size);
|
||||
*out_ini1 = NULL;
|
||||
|
||||
/* Apply IPS patches. */
|
||||
apply_kernel_ips_patches(_kernel, size);
|
||||
@@ -631,6 +733,11 @@ void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kernel_info->embedded_ini_offset != 0) {
|
||||
*out_ini1 = (void *)((uintptr_t)_kernel + kernel_info->embedded_ini_offset);
|
||||
*((volatile uint64_t *)((uintptr_t)_kernel + kernel_info->embedded_ini_ptr)) = (uint64_t)size;
|
||||
}
|
||||
|
||||
/* Apply hooks and patches. */
|
||||
uint8_t *kernel = (uint8_t *)_kernel;
|
||||
size_t free_space_offset = kernel_info->free_code_space_offset;
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
void package2_patch_kernel(void *kernel, size_t kernel_size, bool is_sd_kernel);
|
||||
void package2_patch_kernel(void *kernel, size_t kernel_size, bool is_sd_kernel, void **out_ini1);
|
||||
|
||||
#endif
|
||||
@@ -149,6 +149,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
desired_keyblob = MASTERKEY_REVISION_620;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
|
||||
break;
|
||||
default:
|
||||
@@ -223,6 +224,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_600:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
|
||||
|
||||
@@ -59,10 +59,10 @@ static void setup_env(void) {
|
||||
train_dram();
|
||||
}
|
||||
|
||||
|
||||
static void cleanup_env(void) {
|
||||
/* Unmount everything (this causes all open files to be flushed and closed) */
|
||||
nxfs_unmount_all();
|
||||
//console_end();
|
||||
}
|
||||
|
||||
static void exit_callback(int rc) {
|
||||
@@ -118,6 +118,8 @@ int main(int argc, void **argv) {
|
||||
uint32_t boot_memaddr = nxboot_main();
|
||||
/* Wait for the splash screen to have been displayed as long as it should be. */
|
||||
splash_screen_wait_delay();
|
||||
/* Cleanup environment. */
|
||||
cleanup_env();
|
||||
/* Finish boot. */
|
||||
nxboot_finish(boot_memaddr);
|
||||
} else {
|
||||
|
||||
@@ -106,22 +106,27 @@ static int exosphere_ini_handler(void *user, const char *section, const char *na
|
||||
if (strcmp(section, "exosphere") == 0) {
|
||||
if (strcmp(name, EXOSPHERE_TARGETFW_KEY) == 0) {
|
||||
sscanf(value, "%d", &exo_cfg->target_firmware);
|
||||
}
|
||||
if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
|
||||
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
||||
}
|
||||
}
|
||||
if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
|
||||
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
||||
}
|
||||
} else if (strcmp(name, EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -170,8 +175,10 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||
fatal_error("[NXBOOT]: Unable to identify package1!\n");
|
||||
}
|
||||
}
|
||||
case 0x0F:
|
||||
case 0x0F: /* 7.0.0 - 7.0.1 */
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_700;
|
||||
case 0x10: /* 8.0.0 */
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_800;
|
||||
default:
|
||||
fatal_error("[NXBOOT]: Unable to identify package1!\n");
|
||||
}
|
||||
@@ -192,6 +199,14 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
|
||||
fatal_error("[NXBOOT]: Failed to parse BCT.ini!\n");
|
||||
}
|
||||
|
||||
{
|
||||
FILE *flag = fopen("atmosphere/flags/blank_prodinfo.flag", "rb");
|
||||
if (flag != NULL) {
|
||||
exo_cfg.flags |= EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO;
|
||||
fclose(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
|
||||
fatal_error("[NXBOOT]: Invalid Exosphere target firmware!\n");
|
||||
}
|
||||
@@ -412,7 +427,7 @@ uint32_t nxboot_main(void) {
|
||||
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
|
||||
fatal_error("[NXBOOT]: Failed to read the TSEC firmware from Package1loader!\n");
|
||||
}
|
||||
if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
tsec_fw_size = 0x3000;
|
||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
||||
tsec_fw_size = 0x2900;
|
||||
|
||||
@@ -52,7 +52,8 @@ SdmmcPartitionNum g_current_emmc_partition = SDMMC_PARTITION_INVALID;
|
||||
static int mmc_partition_initialize(device_partition_t *devpart) {
|
||||
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
|
||||
|
||||
if (devpart->read_cipher != NULL || devpart->write_cipher != NULL) {
|
||||
/* Allocate the crypto work buffer. */
|
||||
if ((devpart->read_cipher != NULL) || (devpart->write_cipher != NULL)) {
|
||||
devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16);
|
||||
if (devpart->crypto_work_buffer == NULL) {
|
||||
return ENOMEM;
|
||||
@@ -70,6 +71,7 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
|
||||
g_ahb_redirect_enabled = true;
|
||||
}
|
||||
|
||||
/* Initialize hardware. */
|
||||
if (mmcpart->device == &g_sd_device) {
|
||||
if (!g_sd_device_initialized) {
|
||||
int rc = sdmmc_device_sd_init(mmcpart->device, &g_sd_sdmmc, SDMMC_BUS_WIDTH_4BIT, SDMMC_SPEED_SDR104) ? 0 : EIO;
|
||||
@@ -94,13 +96,33 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
|
||||
}
|
||||
|
||||
static void mmc_partition_finalize(device_partition_t *devpart) {
|
||||
free(devpart->crypto_work_buffer);
|
||||
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
|
||||
|
||||
/* Finalize hardware. */
|
||||
if (mmcpart->device == &g_sd_device) {
|
||||
if (g_sd_device_initialized) {
|
||||
sdmmc_device_finish(&g_sd_device);
|
||||
g_sd_device_initialized = false;
|
||||
}
|
||||
devpart->initialized = false;
|
||||
} else if (mmcpart->device == &g_emmc_device) {
|
||||
if (g_emmc_device_initialized) {
|
||||
sdmmc_device_finish(&g_emmc_device);
|
||||
g_emmc_device_initialized = false;
|
||||
}
|
||||
devpart->initialized = false;
|
||||
}
|
||||
|
||||
/* Disable AHB redirection if necessary. */
|
||||
if (g_ahb_redirect_enabled) {
|
||||
mc_disable_ahb_redirect();
|
||||
g_ahb_redirect_enabled = false;
|
||||
}
|
||||
|
||||
/* Free the crypto work buffer. */
|
||||
if (devpart->crypto_work_buffer != NULL) {
|
||||
free(devpart->crypto_work_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <atmosphere.h>
|
||||
#include "utils.h"
|
||||
#include "masterkey.h"
|
||||
#include "stratosphere.h"
|
||||
@@ -86,10 +87,22 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||
}
|
||||
|
||||
/* Perform any patches we want to the NX kernel. */
|
||||
package2_patch_kernel(kernel, kernel_size, is_sd_kernel);
|
||||
|
||||
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
|
||||
|
||||
/* Ensure we know where embedded INI is if present, and we don't if not. */
|
||||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
||||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
|
||||
fatal_error("Error: inappropriate kernel embedded ini context");
|
||||
}
|
||||
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
|
||||
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
|
||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
|
||||
} else {
|
||||
/* On 8.0.0, place INI1 right after kernelldr for our sanity. */
|
||||
package2->metadata.section_offsets[PACKAGE2_SECTION_INI1] = package2->metadata.section_offsets[PACKAGE2_SECTION_KERNEL] + package2->metadata.section_sizes[PACKAGE2_SECTION_KERNEL];
|
||||
}
|
||||
|
||||
/* Perform any patches to the INI1, rebuilding it (This is where our built-in sysmodules will be added.) */
|
||||
rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware);
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilt INI1...\n");
|
||||
@@ -187,10 +200,15 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
|
||||
}
|
||||
|
||||
/* Ensure no overlap with later sections. */
|
||||
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
|
||||
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
|
||||
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
|
||||
return false;
|
||||
if (metadata->section_sizes[section] != 0) {
|
||||
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
|
||||
if (metadata->section_sizes[later_section] == 0) {
|
||||
continue;
|
||||
}
|
||||
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
|
||||
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1202,6 +1202,9 @@ void sdmmc_finish(sdmmc_t *sdmmc)
|
||||
|
||||
/* Power cycle for 100ms without power. */
|
||||
mdelay(100);
|
||||
|
||||
/* Disable the regulator. */
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
}
|
||||
|
||||
/* Force a register read to refresh the clock control value. */
|
||||
|
||||
@@ -103,20 +103,12 @@ _content_headers:
|
||||
.asciz "ams_mitm"
|
||||
.align 5
|
||||
|
||||
/* boot_100 content header */
|
||||
.word __boot_100_kip_start__
|
||||
.word __boot_100_kip_size__
|
||||
/* boot content header */
|
||||
.word __boot_kip_start__
|
||||
.word __boot_kip_size__
|
||||
.word CONTENT_TYPE_KIP
|
||||
.word 0xCCCCCCCC
|
||||
.asciz "boot_100"
|
||||
.align 5
|
||||
|
||||
/* boot_200 content header */
|
||||
.word __boot_200_kip_start__
|
||||
.word __boot_200_kip_size__
|
||||
.word CONTENT_TYPE_KIP
|
||||
.word 0xCCCCCCCC
|
||||
.asciz "boot_200"
|
||||
.asciz "boot"
|
||||
.align 5
|
||||
|
||||
/* exosphere content header */
|
||||
@@ -191,6 +183,14 @@ _content_headers:
|
||||
.asciz "sm"
|
||||
.align 5
|
||||
|
||||
/* spl content header */
|
||||
.word __spl_kip_start__
|
||||
.word __spl_kip_size__
|
||||
.word CONTENT_TYPE_KIP
|
||||
.word 0xCCCCCCCC
|
||||
.asciz "spl"
|
||||
.align 5
|
||||
|
||||
/* splash_screen content header */
|
||||
.word __splash_screen_bmp_start__
|
||||
.word __splash_screen_bmp_size__
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "pm_kip.h"
|
||||
#include "sm_kip.h"
|
||||
#include "ams_mitm_kip.h"
|
||||
#include "boot_100_kip.h"
|
||||
#include "boot_200_kip.h"
|
||||
#include "boot_kip.h"
|
||||
#include "spl_kip.h"
|
||||
#undef u8
|
||||
#undef u32
|
||||
|
||||
@@ -45,18 +45,15 @@ static bool g_stratosphere_loader_enabled = true;
|
||||
static bool g_stratosphere_sm_enabled = true;
|
||||
static bool g_stratosphere_pm_enabled = true;
|
||||
static bool g_stratosphere_ams_mitm_enabled = true;
|
||||
static bool g_stratosphere_boot_enabled = false;
|
||||
static bool g_stratosphere_spl_enabled = true;
|
||||
static bool g_stratosphere_boot_enabled = true;
|
||||
|
||||
extern const uint8_t boot_100_kip[], boot_200_kip[];
|
||||
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], ams_mitm_kip[];
|
||||
extern const uint32_t boot_100_kip_size, boot_200_kip_size;
|
||||
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, ams_mitm_kip_size;
|
||||
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ams_mitm_kip[];
|
||||
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, spl_kip_size, boot_kip_size, ams_mitm_kip_size;
|
||||
|
||||
/* GCC doesn't consider the size as const... we have to write it ourselves. */
|
||||
|
||||
ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
||||
const uint8_t *boot_kip = NULL;
|
||||
uint32_t boot_kip_size = 0;
|
||||
uint32_t num_processes = 0;
|
||||
uint8_t *data;
|
||||
|
||||
@@ -64,14 +61,6 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
||||
return g_stratosphere_ini1;
|
||||
}
|
||||
|
||||
if (target_firmware <= ATMOSPHERE_TARGET_FIRMWARE_100) {
|
||||
boot_kip = boot_100_kip;
|
||||
boot_kip_size = boot_100_kip_size;
|
||||
} else {
|
||||
boot_kip = boot_200_kip;
|
||||
boot_kip_size = boot_200_kip_size;
|
||||
}
|
||||
|
||||
size_t size = sizeof(ini1_header_t);
|
||||
|
||||
/* Calculate our processes' sizes. */
|
||||
@@ -90,6 +79,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
||||
num_processes++;
|
||||
}
|
||||
|
||||
if (g_stratosphere_spl_enabled) {
|
||||
size += spl_kip_size;
|
||||
num_processes++;
|
||||
}
|
||||
|
||||
if (g_stratosphere_ams_mitm_enabled) {
|
||||
size += ams_mitm_kip_size;
|
||||
num_processes++;
|
||||
@@ -129,6 +123,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
||||
data += sm_kip_size;
|
||||
}
|
||||
|
||||
if (g_stratosphere_spl_enabled) {
|
||||
memcpy(data, spl_kip, spl_kip_size);
|
||||
data += spl_kip_size;
|
||||
}
|
||||
|
||||
if (g_stratosphere_ams_mitm_enabled) {
|
||||
memcpy(data, ams_mitm_kip, ams_mitm_kip_size);
|
||||
data += ams_mitm_kip_size;
|
||||
|
||||
@@ -168,9 +168,9 @@ __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||
|
||||
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
||||
{
|
||||
if(as <= bs && bs <= ae)
|
||||
if(as <= bs && bs < ae)
|
||||
return true;
|
||||
if(bs <= as && as <= be)
|
||||
if(bs <= as && as < be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ clean:
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all $(OUTPUT).enc
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
|
||||
@@ -1202,6 +1202,9 @@ void sdmmc_finish(sdmmc_t *sdmmc)
|
||||
|
||||
/* Power cycle for 100ms without power. */
|
||||
mdelay(100);
|
||||
|
||||
/* Disable the regulator. */
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
}
|
||||
|
||||
/* Force a register read to refresh the clock control value. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
MODULES := loader pm sm boot ams_mitm eclct.stub creport fatal dmnt
|
||||
MODULES := loader pm sm boot ams_mitm spl eclct.stub ro creport fatal dmnt
|
||||
|
||||
SUBFOLDERS := libstratosphere $(MODULES)
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
"svcMapDeviceAddressSpaceAligned": "0x5a",
|
||||
"svcUnmapDeviceAddressSpace": "0x5c",
|
||||
"svcGetSystemInfo": "0x6f",
|
||||
"svcManageNamedPort": "0x71",
|
||||
"svcCallSecureMonitor": "0x7F"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,23 @@ extern "C" {
|
||||
void __libnx_initheap(void);
|
||||
void __appInit(void);
|
||||
void __appExit(void);
|
||||
|
||||
/* Exception handling. */
|
||||
alignas(16) u8 __nx_exception_stack[0x1000];
|
||||
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx);
|
||||
u64 __stratosphere_title_id = 0x010041544D530000ul;
|
||||
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
|
||||
}
|
||||
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
||||
StratosphereCrashHandler(ctx);
|
||||
}
|
||||
|
||||
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
|
||||
/* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */
|
||||
Utils::RebootToFatalError(ctx);
|
||||
}
|
||||
|
||||
void __libnx_initheap(void) {
|
||||
void* addr = nx_inner_heap;
|
||||
@@ -58,15 +73,12 @@ void __appInit(void) {
|
||||
|
||||
SetFirmwareVersionForLibnx();
|
||||
|
||||
rc = smInitialize();
|
||||
if (R_FAILED(rc)) {
|
||||
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
|
||||
}
|
||||
|
||||
rc = fsInitialize();
|
||||
if (R_FAILED(rc)) {
|
||||
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
|
||||
}
|
||||
DoWithSmSession([&]() {
|
||||
rc = fsInitialize();
|
||||
if (R_FAILED(rc)) {
|
||||
std::abort();
|
||||
}
|
||||
});
|
||||
|
||||
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||
}
|
||||
@@ -74,7 +86,6 @@ void __appInit(void) {
|
||||
void __appExit(void) {
|
||||
/* Cleanup services. */
|
||||
fsExit();
|
||||
smExit();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -85,10 +96,10 @@ int main(int argc, char **argv)
|
||||
LaunchAllMitmModules();
|
||||
|
||||
if (R_FAILED(initializer_thread.Initialize(&Utils::InitializeThreadFunc, NULL, 0x4000, 0x15))) {
|
||||
/* TODO: Panic. */
|
||||
std::abort();
|
||||
}
|
||||
if (R_FAILED(initializer_thread.Start())) {
|
||||
/* TODO: Panic. */
|
||||
std::abort();
|
||||
}
|
||||
|
||||
/* Wait for all mitm modules to end. */
|
||||
|
||||
32
stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp
Normal file
32
stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "bpc_ams_service.hpp"
|
||||
#include "bpcmitm_reboot_manager.hpp"
|
||||
|
||||
Result BpcAtmosphereService::RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx) {
|
||||
if (ctx.buffer == nullptr || ctx.num_elements != 1) {
|
||||
return ResultKernelConnectionClosed;
|
||||
}
|
||||
|
||||
/* Reboot to fusee with the input context. */
|
||||
BpcRebootManager::RebootForFatalError(ctx.buffer);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
34
stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp
Normal file
34
stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "../utils.hpp"
|
||||
|
||||
enum BpcAtmosphereCmd : u32 {
|
||||
BpcAtmosphereCmd_RebootToFatalError = 65000,
|
||||
};
|
||||
|
||||
class BpcAtmosphereService : public IServiceObject {
|
||||
private:
|
||||
Result RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx);
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
MakeServiceCommandMeta<BpcAtmosphereCmd_RebootToFatalError, &BpcAtmosphereService::RebootToFatalError>(),
|
||||
};
|
||||
};
|
||||
@@ -25,7 +25,7 @@ enum BpcCmd : u32 {
|
||||
BpcCmd_RebootSystem = 1,
|
||||
};
|
||||
|
||||
class BpcMitmService : public IMitmServiceObject {
|
||||
class BpcMitmService : public IMitmServiceObject {
|
||||
public:
|
||||
BpcMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||
/* ... */
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "bpcmitm_main.hpp"
|
||||
#include "bpc_mitm_service.hpp"
|
||||
#include "bpc_ams_service.hpp"
|
||||
#include "bpcmitm_reboot_manager.hpp"
|
||||
|
||||
#include "../utils.hpp"
|
||||
@@ -46,6 +47,10 @@ void BpcMitmMain(void *arg) {
|
||||
}
|
||||
AddMitmServerToManager<BpcMitmService>(server_manager, service_name, 13);
|
||||
|
||||
/* Extension: Allow for reboot-to-error. */
|
||||
/* Must be managed port in order for sm to be able to access. */
|
||||
server_manager->AddWaitable(new ManagedPortServer<BpcAtmosphereService>("bpc:ams", 1));
|
||||
|
||||
/* Loop forever, servicing our services. */
|
||||
server_manager->Process();
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ static void ClearIram() {
|
||||
memset(g_work_page, 0xFF, sizeof(g_work_page));
|
||||
|
||||
/* Overwrite all of IRAM with FFs. */
|
||||
for (size_t ofs = 0; ofs < IRAM_PAYLOAD_MAX_SIZE; ofs += sizeof(g_work_page)) {
|
||||
CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, sizeof(g_work_page));
|
||||
for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) {
|
||||
CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,3 +99,24 @@ Result BpcRebootManager::PerformReboot() {
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
void BpcRebootManager::RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
|
||||
/* Ensure clean IRAM state. */
|
||||
ClearIram();
|
||||
|
||||
|
||||
/* Copy in payload. */
|
||||
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
||||
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
|
||||
}
|
||||
|
||||
memcpy(g_work_page, ctx, sizeof(*ctx));
|
||||
CopyToIram(IRAM_PAYLOAD_BASE + IRAM_PAYLOAD_MAX_SIZE, g_work_page, sizeof(g_work_page));
|
||||
|
||||
/* If we don't actually have a payload loaded, just go to RCM. */
|
||||
if (!g_payload_loaded) {
|
||||
RebootToRcm();
|
||||
}
|
||||
|
||||
RebootToIramPayload();
|
||||
}
|
||||
@@ -18,7 +18,9 @@
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#define IRAM_PAYLOAD_MAX_SIZE 0x2F000
|
||||
#define IRAM_BASE 0x40000000ull
|
||||
#define IRAM_SIZE 0x40000
|
||||
#define IRAM_PAYLOAD_MAX_SIZE 0x2E000
|
||||
#define IRAM_PAYLOAD_BASE 0x40010000ull
|
||||
|
||||
enum class BpcRebootType : u32 {
|
||||
@@ -31,4 +33,5 @@ class BpcRebootManager {
|
||||
public:
|
||||
static void Initialize();
|
||||
static Result PerformReboot();
|
||||
static void RebootForFatalError(AtmosphereFatalErrorContext *ctx);
|
||||
};
|
||||
112
stratosphere/ams_mitm/source/fs_mitm/fs_file_storage.cpp
Normal file
112
stratosphere/ams_mitm/source/fs_mitm/fs_file_storage.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "../utils.hpp"
|
||||
#include "fs_file_storage.hpp"
|
||||
|
||||
Result FileStorage::UpdateSize() {
|
||||
if (this->size == InvalidSize) {
|
||||
return this->file->GetSize(&this->size);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result FileStorage::Read(void *buffer, size_t size, u64 offset) {
|
||||
Result rc;
|
||||
u64 read_size;
|
||||
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
||||
return rc;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
return this->file->Read(&read_size, offset, buffer, size);
|
||||
}
|
||||
|
||||
Result FileStorage::Write(void *buffer, size_t size, u64 offset) {
|
||||
Result rc;
|
||||
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
||||
return rc;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
return this->file->Write(offset, buffer, size);
|
||||
}
|
||||
|
||||
Result FileStorage::Flush() {
|
||||
return this->file->Flush();
|
||||
}
|
||||
|
||||
Result FileStorage::GetSize(u64 *out_size) {
|
||||
Result rc = this->UpdateSize();
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out_size = this->size;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result FileStorage::SetSize(u64 size) {
|
||||
this->size = InvalidSize;
|
||||
return this->file->SetSize(size);
|
||||
}
|
||||
|
||||
Result FileStorage::OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) {
|
||||
Result rc;
|
||||
|
||||
switch (operation_type) {
|
||||
case 2: /* TODO: OperationType_Invalidate */
|
||||
case 3: /* TODO: OperationType_Query */
|
||||
if (size == 0) {
|
||||
if (operation_type == 3) {
|
||||
if (out_range_info == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
/* N checks for size == sizeof(*out_range_info) here, but that's because their wrapper api is bad. */
|
||||
std::memset(out_range_info, 0, sizeof(*out_range_info));
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
||||
return rc;
|
||||
}
|
||||
/* N checks for positivity + signed overflow on offset/size here, but we're using unsigned types... */
|
||||
return this->file->OperateRange(operation_type, offset, size, out_range_info);
|
||||
default:
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
}
|
||||
54
stratosphere/ams_mitm/source/fs_mitm/fs_file_storage.hpp
Normal file
54
stratosphere/ams_mitm/source/fs_mitm/fs_file_storage.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "fs_shim.h"
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
#include "fs_ifile.hpp"
|
||||
|
||||
class FileStorage : public IStorage {
|
||||
public:
|
||||
static constexpr u64 InvalidSize = UINT64_MAX;
|
||||
private:
|
||||
std::shared_ptr<IFile> base_file;
|
||||
IFile *file;
|
||||
u64 size;
|
||||
public:
|
||||
FileStorage(IFile *f) : base_file(f) {
|
||||
this->file = this->base_file.get();
|
||||
this->size = InvalidSize;
|
||||
};
|
||||
FileStorage(std::shared_ptr<IFile> f) : base_file(f) {
|
||||
this->file = this->base_file.get();
|
||||
this->size = InvalidSize;
|
||||
};
|
||||
virtual ~FileStorage() {
|
||||
/* ... */
|
||||
};
|
||||
protected:
|
||||
Result UpdateSize();
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override;
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override;
|
||||
virtual Result Flush() override;
|
||||
virtual Result GetSize(u64 *out_size) override;
|
||||
virtual Result SetSize(u64 size) override;
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
|
||||
};
|
||||
@@ -112,7 +112,6 @@ class IROStorage : public IStorage {
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) = 0;
|
||||
};
|
||||
|
||||
|
||||
class ProxyStorage : public IStorage {
|
||||
private:
|
||||
FsStorage *base_storage;
|
||||
@@ -172,4 +171,4 @@ class ROProxyStorage : public IROStorage {
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
113
stratosphere/ams_mitm/source/fs_mitm/fs_memory_storage.hpp
Normal file
113
stratosphere/ams_mitm/source/fs_mitm/fs_memory_storage.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "fs_shim.h"
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
class MemoryStorage : public IStorage {
|
||||
private:
|
||||
u8 * const buffer;
|
||||
const u64 size;
|
||||
public:
|
||||
MemoryStorage(void *b, u64 sz) : buffer(static_cast<u8 *>(b)), size(sz) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~MemoryStorage() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
std::memcpy(buffer, this->buffer + offset, size);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
std::memcpy(this->buffer + offset, buffer, size);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
*out_size = this->size;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result SetSize(u64 size) override {
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
switch (operation_type) {
|
||||
case 2: /* TODO: OperationType_Invalidate */
|
||||
return ResultSuccess;
|
||||
case 3: /* TODO: OperationType_Query */
|
||||
if (out_range_info == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
/* N checks for size == sizeof(*out_range_info) here, but that's because their wrapper api is bad. */
|
||||
std::memset(out_range_info, 0, sizeof(*out_range_info));
|
||||
return ResultSuccess;
|
||||
default:
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ReadOnlyMemoryStorage : public MemoryStorage {
|
||||
public:
|
||||
ReadOnlyMemoryStorage(const void *b, u64 sz) : MemoryStorage(const_cast<void *>(b), sz) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~ReadOnlyMemoryStorage() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
};
|
||||
@@ -27,11 +27,14 @@
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "fsmitm_romstorage.hpp"
|
||||
#include "fsmitm_layeredrom.hpp"
|
||||
#include "fsmitm_utils.hpp"
|
||||
|
||||
#include "fs_dir_utils.hpp"
|
||||
#include "fs_save_utils.hpp"
|
||||
#include "fs_subdirectory_filesystem.hpp"
|
||||
#include "fs_directory_savedata_filesystem.hpp"
|
||||
#include "fs_file_storage.hpp"
|
||||
#include "fs_memory_storage.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
|
||||
@@ -261,16 +264,20 @@ Result FsMitmService::OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out
|
||||
const bool is_sysmodule = TitleIdIsSystem(this->title_id);
|
||||
const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write");
|
||||
const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read");
|
||||
const bool has_blank_cal0_flag = ShouldBlankProdInfo();
|
||||
if (bis_partition_id == BisStorageId_Boot0) {
|
||||
storage = std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->title_id));
|
||||
} else if (bis_partition_id == BisStorageId_Prodinfo) {
|
||||
/* PRODINFO should *never* be writable. */
|
||||
if (is_sysmodule || has_cal0_read_flag) {
|
||||
if (has_blank_cal0_flag) {
|
||||
storage = std::make_shared<IStorageInterface>(new MitmProxyStorage(std::make_unique<ReadOnlyMemoryStorage>(Utils::GetBlankProdInfoBuffer(), ProdInfoSize), bis_storage.s));
|
||||
} else if (is_sysmodule || has_cal0_read_flag) {
|
||||
storage = std::make_shared<IStorageInterface>(new ROProxyStorage(bis_storage));
|
||||
} else {
|
||||
/* Do not allow non-sysmodules to read *or* write CAL0. */
|
||||
fsStorageClose(&bis_storage);
|
||||
return ResultFsPermissionDenied;
|
||||
rc = ResultFsPermissionDenied;
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
if (is_sysmodule || has_bis_write_flag) {
|
||||
|
||||
@@ -44,7 +44,7 @@ class FsMitmService : public IMitmServiceObject {
|
||||
bool should_override_contents;
|
||||
public:
|
||||
FsMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||
if (Utils::HasSdDisableMitMFlag(this->title_id)) {
|
||||
if (this->title_id == TitleId_Settings || Utils::HasSdDisableMitMFlag(this->title_id)) {
|
||||
this->should_override_contents = false;
|
||||
} else {
|
||||
this->should_override_contents = (this->title_id >= TitleId_ApplicationStart || Utils::HasSdMitMFlag(this->title_id)) && Utils::HasOverrideButton(this->title_id);
|
||||
@@ -61,11 +61,11 @@ class FsMitmService : public IMitmServiceObject {
|
||||
|
||||
/* TODO: intercepting everything seems to cause issues with sleep mode, for some reason. */
|
||||
/* Figure out why, and address it. */
|
||||
if (tid == TitleId_AppletQlaunch) {
|
||||
if (tid == TitleId_AppletQlaunch || tid == TitleId_AppletMaintenanceMenu) {
|
||||
has_launched_qlaunch = true;
|
||||
}
|
||||
|
||||
return has_launched_qlaunch || tid == TitleId_Ns || tid >= TitleId_ApplicationStart || Utils::HasSdMitMFlag(tid);
|
||||
return has_launched_qlaunch || tid == TitleId_Settings || tid == TitleId_Ns || tid >= TitleId_ApplicationStart || Utils::HasSdMitMFlag(tid);
|
||||
}
|
||||
|
||||
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||
|
||||
59
stratosphere/ams_mitm/source/fs_mitm/fsmitm_utils.hpp
Normal file
59
stratosphere/ams_mitm/source/fs_mitm/fsmitm_utils.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
class MitmProxyStorage : public IStorage {
|
||||
private:
|
||||
Service srv_holder;
|
||||
std::unique_ptr<IStorage> fwd_storage;
|
||||
public:
|
||||
MitmProxyStorage(std::unique_ptr<IStorage> st, Service sr = {}) : srv_holder(sr), fwd_storage(std::move(st)) {
|
||||
/* ... */
|
||||
}
|
||||
virtual ~MitmProxyStorage() {
|
||||
if (serviceIsActive(&srv_holder)) {
|
||||
serviceClose(&srv_holder);
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
return this->fwd_storage->Read(buffer, size, offset);
|
||||
}
|
||||
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
return this->fwd_storage->Write(buffer, size, offset);
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return this->fwd_storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
return this->fwd_storage->GetSize(out_size);
|
||||
}
|
||||
|
||||
virtual Result SetSize(u64 size) override {
|
||||
return this->fwd_storage->SetSize(size);
|
||||
}
|
||||
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return this->fwd_storage->OperateRange(operation_type, offset, size, out_range_info);
|
||||
}
|
||||
};
|
||||
@@ -35,12 +35,12 @@ void NsMitmMain(void *arg) {
|
||||
Utils::WaitSdInitialized();
|
||||
|
||||
/* Ensure we can talk to NS. */
|
||||
{
|
||||
DoWithSmSession([&]() {
|
||||
if (R_FAILED(nsInitialize())) {
|
||||
std::abort();
|
||||
}
|
||||
nsExit();
|
||||
}
|
||||
});
|
||||
|
||||
/* Create server manager */
|
||||
auto server_manager = new WaitableManager(1);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include <atomic>
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ini.h"
|
||||
|
||||
#include "set_mitm/setsys_settings_items.hpp"
|
||||
#include "bpc_mitm/bpcmitm_reboot_manager.hpp"
|
||||
|
||||
static FsFileSystem g_sd_filesystem = {0};
|
||||
static HosSignal g_sd_signal;
|
||||
@@ -59,10 +60,13 @@ static HblOverrideConfig g_hbl_override_config = {
|
||||
static char g_config_ini_data[0x800];
|
||||
|
||||
/* Backup file for CAL0 partition. */
|
||||
static constexpr size_t ProdinfoSize = 0x8000;
|
||||
static FsFile g_cal0_file = {0};
|
||||
static u8 g_cal0_storage_backup[ProdinfoSize];
|
||||
static u8 g_cal0_backup[ProdinfoSize];
|
||||
static u8 g_cal0_storage_backup[ProdInfoSize];
|
||||
static u8 g_cal0_backup[ProdInfoSize];
|
||||
|
||||
static HosMutex g_blank_cal0_lock;
|
||||
static bool g_initialized_blank_cal0 = false;
|
||||
static u8 g_blank_cal0[ProdInfoSize];
|
||||
|
||||
static bool IsHexadecimal(const char *str) {
|
||||
while (*str) {
|
||||
@@ -77,42 +81,44 @@ static bool IsHexadecimal(const char *str) {
|
||||
|
||||
void Utils::InitializeThreadFunc(void *args) {
|
||||
/* Get required services. */
|
||||
Handle tmp_hnd = 0;
|
||||
static const char * const required_active_services[] = {"pcv", "gpio", "pinmux", "psc:c"};
|
||||
for (unsigned int i = 0; i < sizeof(required_active_services) / sizeof(required_active_services[0]); i++) {
|
||||
if (R_FAILED(smGetServiceOriginal(&tmp_hnd, smEncodeName(required_active_services[i])))) {
|
||||
/* TODO: Panic */
|
||||
} else {
|
||||
svcCloseHandle(tmp_hnd);
|
||||
DoWithSmSession([&]() {
|
||||
Handle tmp_hnd = 0;
|
||||
static const char * const required_active_services[] = {"pcv", "gpio", "pinmux", "psc:c"};
|
||||
for (unsigned int i = 0; i < sizeof(required_active_services) / sizeof(required_active_services[0]); i++) {
|
||||
if (R_FAILED(smGetServiceOriginal(&tmp_hnd, smEncodeName(required_active_services[i])))) {
|
||||
std::abort();
|
||||
} else {
|
||||
svcCloseHandle(tmp_hnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/* Mount SD. */
|
||||
while (R_FAILED(fsMountSdcard(&g_sd_filesystem))) {
|
||||
svcSleepThread(1000000ULL);
|
||||
}
|
||||
|
||||
|
||||
/* Back up CAL0, if it's not backed up already. */
|
||||
fsFsCreateDirectory(&g_sd_filesystem, "/atmosphere/automatic_backups");
|
||||
{
|
||||
FsStorage cal0_storage;
|
||||
if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_cal0_storage_backup, ProdinfoSize))) {
|
||||
if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_cal0_storage_backup, ProdInfoSize))) {
|
||||
std::abort();
|
||||
}
|
||||
fsStorageClose(&cal0_storage);
|
||||
|
||||
|
||||
char serial_number[0x40] = {0};
|
||||
memcpy(serial_number, g_cal0_storage_backup + 0x250, 0x18);
|
||||
|
||||
|
||||
|
||||
|
||||
char prodinfo_backup_path[FS_MAX_PATH] = {0};
|
||||
if (strlen(serial_number) > 0) {
|
||||
snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/%s_PRODINFO.bin", serial_number);
|
||||
} else {
|
||||
snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin");
|
||||
}
|
||||
|
||||
fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, ProdinfoSize, 0);
|
||||
|
||||
fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, ProdInfoSize, 0);
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &g_cal0_file))) {
|
||||
bool has_auto_backup = false;
|
||||
size_t read = 0;
|
||||
@@ -121,7 +127,7 @@ void Utils::InitializeThreadFunc(void *args) {
|
||||
is_cal0_valid &= memcmp(g_cal0_backup, "CAL0", 4) == 0;
|
||||
is_cal0_valid &= memcmp(g_cal0_backup + 0x250, serial_number, 0x18) == 0;
|
||||
u32 cal0_size = ((u32 *)g_cal0_backup)[2];
|
||||
is_cal0_valid &= cal0_size + 0x40 <= ProdinfoSize;
|
||||
is_cal0_valid &= cal0_size + 0x40 <= ProdInfoSize;
|
||||
if (is_cal0_valid) {
|
||||
u8 calc_hash[0x20];
|
||||
sha256CalculateHash(calc_hash, g_cal0_backup + 0x40, cal0_size);
|
||||
@@ -129,19 +135,19 @@ void Utils::InitializeThreadFunc(void *args) {
|
||||
}
|
||||
has_auto_backup = is_cal0_valid;
|
||||
}
|
||||
|
||||
|
||||
if (!has_auto_backup) {
|
||||
fsFileSetSize(&g_cal0_file, ProdinfoSize);
|
||||
fsFileWrite(&g_cal0_file, 0, g_cal0_storage_backup, ProdinfoSize);
|
||||
fsFileSetSize(&g_cal0_file, ProdInfoSize);
|
||||
fsFileWrite(&g_cal0_file, 0, g_cal0_storage_backup, ProdInfoSize);
|
||||
fsFileFlush(&g_cal0_file);
|
||||
}
|
||||
|
||||
|
||||
/* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */
|
||||
memset(g_cal0_storage_backup, 0, sizeof(g_cal0_storage_backup));
|
||||
memset(g_cal0_backup, 0, sizeof(g_cal0_backup));
|
||||
std::memset(g_cal0_storage_backup, 0, sizeof(g_cal0_storage_backup));
|
||||
std::memset(g_cal0_backup, 0, sizeof(g_cal0_backup));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check for MitM flags. */
|
||||
FsDir titles_dir;
|
||||
if (R_SUCCEEDED(fsFsOpenDirectory(&g_sd_filesystem, "/atmosphere/titles", FS_DIROPEN_DIRECTORY, &titles_dir))) {
|
||||
@@ -169,7 +175,7 @@ void Utils::InitializeThreadFunc(void *args) {
|
||||
fsFileClose(&f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memset(title_path, 0, sizeof(title_path));
|
||||
strcpy(title_path, "/atmosphere/titles/");
|
||||
strcat(title_path, dir_entry.name);
|
||||
@@ -192,29 +198,35 @@ void Utils::InitializeThreadFunc(void *args) {
|
||||
}
|
||||
fsDirClose(&titles_dir);
|
||||
}
|
||||
|
||||
|
||||
Utils::RefreshConfiguration();
|
||||
|
||||
|
||||
/* Initialize set:sys. */
|
||||
setsysInitialize();
|
||||
|
||||
DoWithSmSession([&]() {
|
||||
if (R_FAILED(setsysInitialize())) {
|
||||
std::abort();
|
||||
}
|
||||
});
|
||||
|
||||
/* Signal SD is initialized. */
|
||||
g_has_initialized = true;
|
||||
|
||||
|
||||
/* Load custom settings configuration. */
|
||||
SettingsItemManager::LoadConfiguration();
|
||||
|
||||
|
||||
/* Signal to waiters that we are ready. */
|
||||
g_sd_signal.Signal();
|
||||
|
||||
|
||||
/* Initialize HID. */
|
||||
{
|
||||
|
||||
while (R_FAILED(hidInitialize())) {
|
||||
while (!g_has_hid_session) {
|
||||
DoWithSmSession([&]() {
|
||||
if (R_SUCCEEDED(hidInitialize())) {
|
||||
g_has_hid_session = true;
|
||||
}
|
||||
});
|
||||
if (!g_has_hid_session) {
|
||||
svcSleepThread(1000000ULL);
|
||||
}
|
||||
|
||||
g_has_hid_session = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +246,7 @@ Result Utils::OpenSdFile(const char *fn, int flags, FsFile *out) {
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
return fsFsOpenFile(&g_sd_filesystem, fn, flags, out);
|
||||
}
|
||||
|
||||
@@ -242,7 +254,7 @@ Result Utils::OpenSdFileForAtmosphere(u64 title_id, const char *fn, int flags, F
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (*fn == '/') {
|
||||
snprintf(path, sizeof(path), "/atmosphere/titles/%016lx%s", title_id, fn);
|
||||
@@ -256,7 +268,7 @@ Result Utils::OpenRomFSSdFile(u64 title_id, const char *fn, int flags, FsFile *o
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
return OpenRomFSFile(&g_sd_filesystem, title_id, fn, flags, out);
|
||||
}
|
||||
|
||||
@@ -264,7 +276,7 @@ Result Utils::OpenSdDir(const char *path, FsDir *out) {
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
return fsFsOpenDirectory(&g_sd_filesystem, path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, out);
|
||||
}
|
||||
|
||||
@@ -272,7 +284,7 @@ Result Utils::OpenSdDirForAtmosphere(u64 title_id, const char *path, FsDir *out)
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
char safe_path[FS_MAX_PATH];
|
||||
if (*path == '/') {
|
||||
snprintf(safe_path, sizeof(safe_path), "/atmosphere/titles/%016lx%s", title_id, path);
|
||||
@@ -286,7 +298,7 @@ Result Utils::OpenRomFSSdDir(u64 title_id, const char *path, FsDir *out) {
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
return OpenRomFSDir(&g_sd_filesystem, title_id, path, out);
|
||||
}
|
||||
|
||||
@@ -318,7 +330,7 @@ bool Utils::HasSdRomfsContent(u64 title_id) {
|
||||
fsFileClose(&data_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Check for romfs folder with non-zero content. */
|
||||
FsDir dir;
|
||||
if (R_FAILED(Utils::OpenRomFSSdDir(title_id, "", &dir))) {
|
||||
@@ -327,7 +339,7 @@ bool Utils::HasSdRomfsContent(u64 title_id) {
|
||||
ON_SCOPE_EXIT {
|
||||
fsDirClose(&dir);
|
||||
};
|
||||
|
||||
|
||||
FsDirectoryEntry dir_entry;
|
||||
u64 read_entries;
|
||||
return R_SUCCEEDED(fsDirRead(&dir, 0, &read_entries, 1, &dir_entry)) && read_entries == 1;
|
||||
@@ -337,40 +349,40 @@ Result Utils::SaveSdFileForAtmosphere(u64 title_id, const char *fn, void *data,
|
||||
if (!IsSdInitialized()) {
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
|
||||
Result rc = ResultSuccess;
|
||||
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (*fn == '/') {
|
||||
snprintf(path, sizeof(path), "/atmosphere/titles/%016lx%s", title_id, fn);
|
||||
} else {
|
||||
snprintf(path, sizeof(path), "/atmosphere/titles/%016lx/%s", title_id, fn);
|
||||
}
|
||||
|
||||
|
||||
/* Unconditionally create. */
|
||||
FsFile f;
|
||||
fsFsCreateFile(&g_sd_filesystem, path, size, 0);
|
||||
|
||||
|
||||
/* Try to open. */
|
||||
rc = fsFsOpenFile(&g_sd_filesystem, path, FS_OPEN_READ | FS_OPEN_WRITE, &f);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Always close, if we opened. */
|
||||
ON_SCOPE_EXIT {
|
||||
fsFileClose(&f);
|
||||
};
|
||||
|
||||
|
||||
/* Try to make it big enough. */
|
||||
rc = fsFileSetSize(&f, size);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Try to write the data. */
|
||||
rc = fsFileWrite(&f, 0, data, size);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -386,14 +398,14 @@ bool Utils::HasTitleFlag(u64 tid, const char *flag) {
|
||||
if (IsSdInitialized()) {
|
||||
FsFile f;
|
||||
char flag_path[FS_MAX_PATH];
|
||||
|
||||
|
||||
memset(flag_path, 0, sizeof(flag_path));
|
||||
snprintf(flag_path, sizeof(flag_path) - 1, "flags/%s.flag", flag);
|
||||
if (R_SUCCEEDED(OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f))) {
|
||||
fsFileClose(&f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Deprecate. */
|
||||
snprintf(flag_path, sizeof(flag_path) - 1, "%s.flag", flag);
|
||||
if (R_SUCCEEDED(OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f))) {
|
||||
@@ -431,7 +443,7 @@ bool Utils::HasSdMitMFlag(u64 tid) {
|
||||
if (IsHblTid(tid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (IsSdInitialized()) {
|
||||
return std::find(g_mitm_flagged_tids.begin(), g_mitm_flagged_tids.end(), tid) != g_mitm_flagged_tids.end();
|
||||
}
|
||||
@@ -449,10 +461,10 @@ Result Utils::GetKeysHeld(u64 *keys) {
|
||||
if (!Utils::IsHidAvailable()) {
|
||||
return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID);
|
||||
}
|
||||
|
||||
|
||||
hidScanInput();
|
||||
*keys = hidKeysHeld(CONTROLLER_P1_AUTO);
|
||||
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
@@ -468,21 +480,21 @@ bool Utils::HasOverrideButton(u64 tid) {
|
||||
/* Disable button override disable for non-applications. */
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Unconditionally refresh loader.ini contents. */
|
||||
RefreshConfiguration();
|
||||
|
||||
|
||||
if (IsHblTid(tid) && HasOverrideKey(&g_hbl_override_config.override_key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
OverrideKey title_cfg = GetTitleOverrideKey(tid);
|
||||
return HasOverrideKey(&title_cfg);
|
||||
}
|
||||
|
||||
static OverrideKey ParseOverrideKey(const char *value) {
|
||||
OverrideKey cfg;
|
||||
|
||||
|
||||
/* Parse on by default. */
|
||||
if (value[0] == '!') {
|
||||
cfg.override_by_default = true;
|
||||
@@ -490,7 +502,7 @@ static OverrideKey ParseOverrideKey(const char *value) {
|
||||
} else {
|
||||
cfg.override_by_default = false;
|
||||
}
|
||||
|
||||
|
||||
/* Parse key combination. */
|
||||
if (strcasecmp(value, "A") == 0) {
|
||||
cfg.key_combination = KEY_A;
|
||||
@@ -531,7 +543,7 @@ static OverrideKey ParseOverrideKey(const char *value) {
|
||||
} else {
|
||||
cfg.key_combination = 0;
|
||||
}
|
||||
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -573,7 +585,7 @@ static int FsMitmIniHandler(void *user, const char *section, const char *name, c
|
||||
static int FsMitmTitleSpecificIniHandler(void *user, const char *section, const char *name, const char *value) {
|
||||
/* We'll output an override key when relevant. */
|
||||
OverrideKey *user_cfg = reinterpret_cast<OverrideKey *>(user);
|
||||
|
||||
|
||||
if (strcasecmp(section, "override_config") == 0) {
|
||||
if (strcasecmp(name, "override_key") == 0) {
|
||||
*user_cfg = ParseOverrideKey(value);
|
||||
@@ -587,27 +599,27 @@ static int FsMitmTitleSpecificIniHandler(void *user, const char *section, const
|
||||
OverrideKey Utils::GetTitleOverrideKey(u64 tid) {
|
||||
OverrideKey cfg = g_default_override_key;
|
||||
char path[FS_MAX_PATH+1] = {0};
|
||||
snprintf(path, FS_MAX_PATH, "/atmosphere/titles/%016lx/config.ini", tid);
|
||||
snprintf(path, FS_MAX_PATH, "/atmosphere/titles/%016lx/config.ini", tid);
|
||||
FsFile cfg_file;
|
||||
|
||||
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, path, FS_OPEN_READ, &cfg_file))) {
|
||||
ON_SCOPE_EXIT { fsFileClose(&cfg_file); };
|
||||
|
||||
|
||||
size_t config_file_size = 0x20000;
|
||||
fsFileGetSize(&cfg_file, &config_file_size);
|
||||
|
||||
|
||||
char *config_buf = reinterpret_cast<char *>(calloc(1, config_file_size + 1));
|
||||
if (config_buf != NULL) {
|
||||
ON_SCOPE_EXIT { free(config_buf); };
|
||||
|
||||
|
||||
/* Read title ini contents. */
|
||||
fsFileRead(&cfg_file, 0, config_buf, config_file_size, &config_file_size);
|
||||
|
||||
|
||||
/* Parse title ini. */
|
||||
ini_parse_string(config_buf, FsMitmTitleSpecificIniHandler, &cfg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -616,20 +628,20 @@ void Utils::RefreshConfiguration() {
|
||||
if (R_FAILED(fsFsOpenFile(&g_sd_filesystem, "/atmosphere/loader.ini", FS_OPEN_READ, &config_file))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
u64 size;
|
||||
if (R_FAILED(fsFileGetSize(&config_file, &size))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
size = std::min(size, (decltype(size))0x7FF);
|
||||
|
||||
|
||||
/* Read in string. */
|
||||
std::fill(g_config_ini_data, g_config_ini_data + 0x800, 0);
|
||||
size_t r_s;
|
||||
fsFileRead(&config_file, 0, g_config_ini_data, size, &r_s);
|
||||
fsFileClose(&config_file);
|
||||
|
||||
|
||||
ini_parse_string(g_config_ini_data, FsMitmIniHandler, NULL);
|
||||
}
|
||||
|
||||
@@ -652,3 +664,90 @@ Result Utils::GetSettingsItemBooleanValue(const char *name, const char *key, boo
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Utils::RebootToFatalError(AtmosphereFatalErrorContext *ctx) {
|
||||
BpcRebootManager::RebootForFatalError(ctx);
|
||||
}
|
||||
|
||||
void Utils::EnsureBlankProdInfo() {
|
||||
std::scoped_lock<HosMutex> lk(g_blank_cal0_lock);
|
||||
if (g_initialized_blank_cal0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read CAL0 in from NAND. */
|
||||
{
|
||||
FsStorage cal0_storage;
|
||||
if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_blank_cal0, ProdInfoSize))) {
|
||||
std::abort();
|
||||
}
|
||||
fsStorageClose(&cal0_storage);
|
||||
}
|
||||
|
||||
if (!IsCal0Valid(g_blank_cal0)) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
const char blank_serial[] = "XAW00000000000";
|
||||
std::memcpy(&g_blank_cal0[0x250], blank_serial, sizeof(blank_serial) - 1);
|
||||
|
||||
static constexpr size_t NumErase = 7;
|
||||
|
||||
for (size_t i = 0; i < NumErase; i++) {
|
||||
static constexpr size_t s_erase_offsets[NumErase] = {0xAE0, 0x3AE0, 0x35E1, 0x36E1, 0x2B0, 0x3D70, 0x3FC0};
|
||||
static constexpr size_t s_erase_sizes[NumErase] = {0x800, 0x130, 0x6, 0x6, 0x180, 0x240, 0x240};
|
||||
std::memset(&g_blank_cal0[s_erase_offsets[i]], 0, s_erase_sizes[i]);
|
||||
}
|
||||
|
||||
static constexpr size_t NumHashes = 2;
|
||||
{
|
||||
static constexpr size_t s_hash_offsets[NumHashes] = {0x12E0, 0x20};
|
||||
static constexpr size_t s_data_offsets[NumHashes] = {0xAE0, 0x40};
|
||||
const size_t data_sizes[NumHashes] = {*reinterpret_cast<u32 *>(&g_blank_cal0[0xAD0]), *reinterpret_cast<u32 *>(&g_blank_cal0[0x8])};
|
||||
for (size_t i = 0; i < NumHashes; i++) {
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
sha256CalculateHash(hash, &g_blank_cal0[s_data_offsets[i]], data_sizes[i]);
|
||||
std::memcpy(&g_blank_cal0[s_hash_offsets[i]], hash, sizeof(hash));
|
||||
}
|
||||
}
|
||||
|
||||
g_initialized_blank_cal0 = true;
|
||||
}
|
||||
|
||||
bool Utils::IsCal0Valid(const u8 *cal0) {
|
||||
bool is_cal0_valid = true;
|
||||
is_cal0_valid &= std::memcmp(cal0, "CAL0", 4) == 0;
|
||||
u32 cal0_size = ((u32 *)cal0)[2];
|
||||
is_cal0_valid &= cal0_size + 0x40 <= ProdInfoSize;
|
||||
if (is_cal0_valid) {
|
||||
u8 calc_hash[0x20];
|
||||
sha256CalculateHash(calc_hash, cal0 + 0x40, cal0_size);
|
||||
is_cal0_valid &= std::memcmp(calc_hash, cal0 + 0x20, sizeof(calc_hash)) == 0;
|
||||
}
|
||||
|
||||
return is_cal0_valid;
|
||||
}
|
||||
|
||||
u16 Utils::GetCrc16(const void *data, size_t size) {
|
||||
static constexpr u16 s_crc_table[0x10] = {
|
||||
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
||||
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
||||
};
|
||||
|
||||
if (data == nullptr) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
u16 crc16 = 0x55AA;
|
||||
const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[data_u8[i] & 0xF]);
|
||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[(data_u8[i] >> 4) & 0xF]);
|
||||
}
|
||||
return crc16;
|
||||
}
|
||||
|
||||
const void *Utils::GetBlankProdInfoBuffer() {
|
||||
EnsureBlankProdInfo();
|
||||
return g_blank_cal0;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ enum BisStorageId : u32 {
|
||||
BisStorageId_SystemProperPartition = 33,
|
||||
};
|
||||
|
||||
static constexpr size_t ProdInfoSize = 0x8000;
|
||||
|
||||
struct OverrideKey {
|
||||
u64 key_combination;
|
||||
bool override_by_default;
|
||||
@@ -61,6 +63,8 @@ class Utils {
|
||||
|
||||
static bool HasSdRomfsContent(u64 title_id);
|
||||
|
||||
static const void *GetBlankProdInfoBuffer();
|
||||
|
||||
/* Delayed Initialization + MitM detection. */
|
||||
static void InitializeThreadFunc(void *args);
|
||||
|
||||
@@ -87,6 +91,15 @@ class Utils {
|
||||
static Result GetSettingsItemValue(const char *name, const char *key, void *out, size_t max_size, u64 *out_size);
|
||||
|
||||
static Result GetSettingsItemBooleanValue(const char *name, const char *key, bool *out);
|
||||
|
||||
/* CRC util. */
|
||||
static u16 GetCrc16(const void *data, size_t size);
|
||||
|
||||
/* Error occurred. */
|
||||
static void RebootToFatalError(AtmosphereFatalErrorContext *ctx);
|
||||
private:
|
||||
static void RefreshConfiguration();
|
||||
|
||||
static void EnsureBlankProdInfo();
|
||||
static bool IsCal0Valid(const u8 *cal0);
|
||||
};
|
||||
@@ -16,6 +16,12 @@ ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
||||
AMSREV := $(AMSREV)-dirty
|
||||
endif
|
||||
|
||||
define _bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`"_end[];" > `(echo $(<F) | tr . _ | tr - _)`.h
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`"[];" >> `(echo $(<F) | tr . _ | tr - _)`.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`_size";" >> `(echo $(<F) | tr . _ | tr - _)`.h
|
||||
endef
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
@@ -27,7 +33,7 @@ endif
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
SOURCES := source source/i2c_driver source/updater
|
||||
DATA := data
|
||||
INCLUDES := include ../../common/include
|
||||
EXEFS_SRC := exefs_src
|
||||
@@ -69,14 +75,14 @@ export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(TOPDIR)/../../fusee/fusee-primary
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
@@ -116,19 +122,23 @@ else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
.PHONY: $(BUILD) check_fusee clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
check_fusee:
|
||||
@$(MAKE) -C $(TOPDIR)/../../fusee/fusee-primary all
|
||||
|
||||
$(BUILD): check_fusee
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET)_100.kip $(TARGET)_100.elf $(TARGET)_200.kip $(TARGET)_200.elf
|
||||
@$(MAKE) -C $(TOPDIR)/../../fusee/fusee-primary clean
|
||||
@rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -140,20 +150,20 @@ DEPENDS := $(OFILES:.o=.d)
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT)_100.kip $(OUTPUT)_200.kip
|
||||
all : $(OUTPUT).kip
|
||||
|
||||
$(OUTPUT)_100.kip : $(OUTPUT)_100.elf
|
||||
$(OUTPUT)_200.kip : $(OUTPUT)_200.elf
|
||||
$(OUTPUT).kip : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT)_100.kip : APP_JSON = $(TOPDIR)/boot_100.json
|
||||
$(OUTPUT)_200.kip : APP_JSON = $(TOPDIR)/boot_200.json
|
||||
|
||||
$(OUTPUT)_100.elf : $(OFILES)
|
||||
$(OUTPUT)_200.elf : $(OFILES)
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(_bin2o)
|
||||
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "boot",
|
||||
"title_id": "0x0100000000000005",
|
||||
"main_thread_stack_size": "0x1000",
|
||||
"main_thread_stack_size": "0x8000",
|
||||
"main_thread_priority": 27,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 1,
|
||||
@@ -1,171 +0,0 @@
|
||||
{
|
||||
"name": "boot",
|
||||
"title_id": "0x0100000000000005",
|
||||
"main_thread_stack_size": "0x1000",
|
||||
"main_thread_priority": 27,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 1,
|
||||
"kernel_capabilities": [
|
||||
{
|
||||
"type": "handle_table_size",
|
||||
"value": 128
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
"svcSetHeapSize": "0x01",
|
||||
"svcSetMemoryPermission": "0x02",
|
||||
"svcSetMemoryAttribute": "0x03",
|
||||
"svcMapMemory": "0x04",
|
||||
"svcUnmapMemory": "0x05",
|
||||
"svcQueryMemory": "0x06",
|
||||
"svcExitProcess": "0x07",
|
||||
"svcCreateThread": "0x08",
|
||||
"svcStartThread": "0x09",
|
||||
"svcExitThread": "0x0A",
|
||||
"svcSleepThread": "0x0B",
|
||||
"svcGetThreadPriority": "0x0C",
|
||||
"svcSetThreadPriority": "0x0D",
|
||||
"svcGetThreadCoreMask": "0x0E",
|
||||
"svcSetThreadCoreMask": "0x0F",
|
||||
"svcGetCurrentProcessorNumber": "0x10",
|
||||
"svcSignalEvent": "0x11",
|
||||
"svcClearEvent": "0x12",
|
||||
"svcMapSharedMemory": "0x13",
|
||||
"svcUnmapSharedMemory": "0x14",
|
||||
"svcCreateTransferMemory": "0x15",
|
||||
"svcCloseHandle": "0x16",
|
||||
"svcResetSignal": "0x17",
|
||||
"svcWaitSynchronization": "0x18",
|
||||
"svcCancelSynchronization": "0x19",
|
||||
"svcArbitrateLock": "0x1A",
|
||||
"svcArbitrateUnlock": "0x1B",
|
||||
"svcWaitProcessWideKeyAtomic": "0x1C",
|
||||
"svcSignalProcessWideKey": "0x1D",
|
||||
"svcGetSystemTick": "0x1E",
|
||||
"svcConnectToNamedPort": "0x1F",
|
||||
"svcSendSyncRequestLight": "0x20",
|
||||
"svcSendSyncRequest": "0x21",
|
||||
"svcSendSyncRequestWithUserBuffer": "0x22",
|
||||
"svcSendAsyncRequestWithUserBuffer": "0x23",
|
||||
"svcGetProcessId": "0x24",
|
||||
"svcGetThreadId": "0x25",
|
||||
"svcBreak": "0x26",
|
||||
"svcOutputDebugString": "0x27",
|
||||
"svcReturnFromException": "0x28",
|
||||
"svcGetInfo": "0x29",
|
||||
"svcCreateInterruptEvent": "0x53",
|
||||
"svcQueryIoMapping": "0x55",
|
||||
"svcCreateDeviceAddressSpace": "0x56",
|
||||
"svcAttachDeviceAddressSpace": "0x57",
|
||||
"svcDetachDeviceAddressSpace": "0x58",
|
||||
"svcMapDeviceAddressSpaceAligned": "0x5A",
|
||||
"svcUnmapDeviceAddressSpace": "0x5C",
|
||||
"svcFlushProcessDataCache": "0x5F",
|
||||
"svcCallSecureMonitor": "0x7F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x50003000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x54200000",
|
||||
"size": "0x3000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x54300000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x60006000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x6000D000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x70000000",
|
||||
"size": "0x4000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x7000C000",
|
||||
"size": "0x2000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x7000E000",
|
||||
"size": "0x4000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x700E3000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "irq_pair",
|
||||
"value": [
|
||||
70,
|
||||
116
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "irq_pair",
|
||||
"value": [
|
||||
124,
|
||||
152
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "irq_pair",
|
||||
"value": [
|
||||
85,
|
||||
95
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
374
stratosphere/boot/source/boot_battery_driver.cpp
Normal file
374
stratosphere/boot/source/boot_battery_driver.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_battery_driver.hpp"
|
||||
|
||||
const Max17050Parameters *BatteryDriver::GetBatteryParameters() {
|
||||
const u32 battery_version = Boot::GetBatteryVersion();
|
||||
const u32 battery_vendor = Boot::GetBatteryVendor();
|
||||
|
||||
if (battery_version == 2) {
|
||||
if (battery_vendor == 'M') {
|
||||
return &Max17050Params2M;
|
||||
} else {
|
||||
return &Max17050Params2;
|
||||
}
|
||||
} else if (battery_version == 1) {
|
||||
return &Max17050Params1;
|
||||
} else {
|
||||
switch (battery_vendor) {
|
||||
case 'M':
|
||||
return &Max17050ParamsM;
|
||||
case 'R':
|
||||
return &Max17050ParamsR;
|
||||
case 'A':
|
||||
default:
|
||||
return &Max17050ParamsA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result BatteryDriver::Read(u8 addr, u16 *out) {
|
||||
return Boot::ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
Result BatteryDriver::Write(u8 addr, u16 val) {
|
||||
return Boot::WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
Result BatteryDriver::ReadWrite(u8 addr, u16 mask, u16 val) {
|
||||
Result rc;
|
||||
u16 cur_val;
|
||||
if (R_FAILED((rc = this->Read(addr, &cur_val)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
const u16 new_val = (cur_val & ~mask) | val;
|
||||
if (R_FAILED((rc = this->Write(addr, new_val)))) {
|
||||
return rc;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool BatteryDriver::WriteValidate(u8 addr, u16 val) {
|
||||
/* Nintendo doesn't seem to check errors when doing this? */
|
||||
/* It's probably okay, since the value does get validated. */
|
||||
/* That said, we will validate the read to avoid uninit data problems. */
|
||||
this->Write(addr, val);
|
||||
svcSleepThread(3'000'000ul);
|
||||
|
||||
u16 new_val;
|
||||
return R_SUCCEEDED(this->Read(addr, &new_val)) && new_val == val;
|
||||
}
|
||||
|
||||
bool BatteryDriver::IsPowerOnReset() {
|
||||
/* N doesn't check result... */
|
||||
u16 val = 0;
|
||||
this->Read(Max17050Status, &val);
|
||||
return (val & 0x0002) == 0x0002;
|
||||
}
|
||||
|
||||
Result BatteryDriver::LockVfSoc() {
|
||||
return this->Write(Max17050SocVfAccess, 0x0000);
|
||||
}
|
||||
|
||||
Result BatteryDriver::UnlockVfSoc() {
|
||||
return this->Write(Max17050SocVfAccess, 0x0080);
|
||||
}
|
||||
|
||||
Result BatteryDriver::LockModelTable() {
|
||||
Result rc;
|
||||
if (R_FAILED((rc = this->Write(Max17050ModelAccess0, 0x0000)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050ModelAccess1, 0x0000)))) {
|
||||
return rc;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::UnlockModelTable() {
|
||||
Result rc;
|
||||
if (R_FAILED((rc = this->Write(Max17050ModelAccess0, 0x0059)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050ModelAccess1, 0x00C4)))) {
|
||||
return rc;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::SetModelTable(const u16 *model_table) {
|
||||
Result rc;
|
||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
||||
if (R_FAILED((rc = this->Write(Max17050ModelChrTblStart + i, model_table[i])))) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool BatteryDriver::IsModelTableLocked() {
|
||||
bool locked = true;
|
||||
|
||||
u16 cur_val = 0;
|
||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
||||
this->Read(Max17050ModelChrTblStart + i, &cur_val);
|
||||
locked &= (cur_val == 0);
|
||||
}
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
bool BatteryDriver::IsModelTableSet(const u16 *model_table) {
|
||||
bool set = true;
|
||||
|
||||
u16 cur_val = 0;
|
||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
||||
this->Read(Max17050ModelChrTblStart + i, &cur_val);
|
||||
set &= (cur_val == model_table[i]);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
Result BatteryDriver::InitializeBatteryParameters() {
|
||||
const Max17050Parameters *params = GetBatteryParameters();
|
||||
Result rc = ResultSuccess;
|
||||
|
||||
if (IsPowerOnReset()) {
|
||||
/* Do initial config. */
|
||||
if (R_FAILED((rc = this->ReadWrite(Max17050MiscCfg, 0x8000, 0x8000)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
svcSleepThread(500'000'000ul);
|
||||
|
||||
if (R_FAILED((rc = this->Write(Max17050Config, 0x7210)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050FilterCfg, 0x8784)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050RelaxCfg, params->relaxcfg)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050LearnCfg, 0x2603)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050FullSocThr, params->fullsocthr)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050IAvgEmpty, params->iavgempty)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Unlock model table, write model table. */
|
||||
do {
|
||||
if (R_FAILED((rc = this->UnlockModelTable()))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->SetModelTable(params->modeltbl)))) {
|
||||
return rc;
|
||||
}
|
||||
} while (!this->IsModelTableSet(params->modeltbl));
|
||||
|
||||
/* Lock model table. */
|
||||
size_t lock_i = 0;
|
||||
while (true) {
|
||||
lock_i++;
|
||||
if (R_FAILED((rc = this->LockModelTable()))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (this->IsModelTableLocked()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_i >= 8) {
|
||||
/* This is regarded as guaranteed success. */
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write custom parameters. */
|
||||
while (!this->WriteValidate(Max17050RComp0, params->rcomp0)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050TempCo, params->tempco)) { /* ... */ }
|
||||
|
||||
if (R_FAILED((rc = this->Write(Max17050IChgTerm, params->ichgterm)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050TGain, params->tgain)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050TOff, params->toff)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
while (!this->WriteValidate(Max17050VEmpty, params->vempty)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050QResidual00, params->qresidual00)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050QResidual10, params->qresidual10)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050QResidual20, params->qresidual20)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050QResidual30, params->qresidual30)) { /* ... */ }
|
||||
|
||||
|
||||
/* Write full capacity parameters. */
|
||||
while (!this->WriteValidate(Max17050FullCap, params->fullcap)) { /* ... */ }
|
||||
if (R_FAILED((rc = this->Write(Max17050DesignCap, params->vffullcap)))) {
|
||||
return rc;
|
||||
}
|
||||
while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ }
|
||||
|
||||
svcSleepThread(350'000'000ul);
|
||||
|
||||
/* Write VFSOC to VFSOC 0. */
|
||||
u16 vfsoc, qh;
|
||||
{
|
||||
if (R_FAILED((rc = this->Read(Max17050SocVf, &vfsoc)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->UnlockVfSoc()))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050SocVf0, vfsoc)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Read(Max17050Qh, &qh)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050Qh0, qh)))) {
|
||||
return rc;
|
||||
}
|
||||
if (R_FAILED((rc = this->LockVfSoc()))) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write cycles. */
|
||||
while (!this->WriteValidate(Max17050Cycles, 0x0060)) { /* ... */ }
|
||||
|
||||
/* Load new capacity parameters. */
|
||||
const u16 remcap = static_cast<u16>((vfsoc * params->vffullcap) / 0x6400);
|
||||
const u16 repcap = static_cast<u16>(remcap * (params->fullcap / params->vffullcap));
|
||||
const u16 dqacc = params->vffullcap / 0x10;
|
||||
while (!this->WriteValidate(Max17050RemCapMix, remcap)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050RemCapRep, repcap)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050DPAcc, 0x0C80)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050DQAcc, dqacc)) { /* ... */ }
|
||||
while (!this->WriteValidate(Max17050FullCap, params->fullcap)) { /* ... */ }
|
||||
if (R_FAILED((rc = this->Write(Max17050DesignCap, params->vffullcap)))) {
|
||||
return rc;
|
||||
}
|
||||
while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ }
|
||||
if (R_FAILED((rc = this->Write(Max17050SocRep, vfsoc)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Finish initialization. */
|
||||
{
|
||||
u16 status;
|
||||
if (R_FAILED((rc = this->Read(Max17050Status, &status)))) {
|
||||
return rc;
|
||||
}
|
||||
while (!this->WriteValidate(Max17050Status, status & 0xFFFD)) { /* ... */ }
|
||||
}
|
||||
if (R_FAILED((rc = this->Write(Max17050CGain, 0x7FFF)))) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::IsBatteryRemoved(bool *out) {
|
||||
/* N doesn't check result, but we will. */
|
||||
u16 val = 0;
|
||||
Result rc = this->Read(Max17050Status, &val);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = (val & 0x0008) == 0x0008;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::GetTemperature(double *out) {
|
||||
u16 val = 0;
|
||||
Result rc = this->Read(Max17050Temperature, &val);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = static_cast<double>(val) * double(0.00390625);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::GetAverageVCell(u32 *out) {
|
||||
u16 val = 0;
|
||||
Result rc = this->Read(Max17050AverageVCell, &val);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = (625 * u32(val >> 3)) / 1000;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::GetSocRep(double *out) {
|
||||
u16 val = 0;
|
||||
Result rc = this->Read(Max17050SocRep, &val);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = static_cast<double>(val) * double(0.00390625);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::GetBatteryPercentage(size_t *out) {
|
||||
double raw_charge;
|
||||
Result rc = this->GetSocRep(&raw_charge);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
int converted_percentage = (((raw_charge - 3.93359375) * 98.0) / 94.2304688) + 2.0;
|
||||
if (converted_percentage < 1) {
|
||||
*out = 1;
|
||||
} else if (converted_percentage > 100) {
|
||||
*out = 100;
|
||||
} else {
|
||||
*out = static_cast<size_t>(converted_percentage);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::SetShutdownTimer() {
|
||||
return this->Write(Max17050ShdnTimer, 0xE000);
|
||||
}
|
||||
|
||||
Result BatteryDriver::GetShutdownEnabled(bool *out) {
|
||||
u16 val = 0;
|
||||
Result rc = this->Read(Max17050Config, &val);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = (val & 0x0040) != 0;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result BatteryDriver::SetShutdownEnabled(bool enabled) {
|
||||
return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000);
|
||||
}
|
||||
64
stratosphere/boot/source/boot_battery_driver.hpp
Normal file
64
stratosphere/boot/source/boot_battery_driver.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "i2c_driver/i2c_api.hpp"
|
||||
#include "boot_battery_parameters.hpp"
|
||||
|
||||
class BatteryDriver {
|
||||
private:
|
||||
I2cSessionImpl i2c_session;
|
||||
public:
|
||||
BatteryDriver() {
|
||||
I2cDriver::Initialize();
|
||||
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max17050);
|
||||
}
|
||||
|
||||
~BatteryDriver() {
|
||||
I2cDriver::CloseSession(this->i2c_session);
|
||||
I2cDriver::Finalize();
|
||||
}
|
||||
private:
|
||||
static const Max17050Parameters *GetBatteryParameters();
|
||||
|
||||
Result Read(u8 addr, u16 *out_data);
|
||||
Result Write(u8 addr, u16 val);
|
||||
Result ReadWrite(u8 addr, u16 mask, u16 val);
|
||||
bool WriteValidate(u8 addr, u16 val);
|
||||
|
||||
bool IsPowerOnReset();
|
||||
Result LockVfSoc();
|
||||
Result UnlockVfSoc();
|
||||
Result LockModelTable();
|
||||
Result UnlockModelTable();
|
||||
bool IsModelTableLocked();
|
||||
Result SetModelTable(const u16 *model_table);
|
||||
bool IsModelTableSet(const u16 *model_table);
|
||||
|
||||
public:
|
||||
Result InitializeBatteryParameters();
|
||||
Result IsBatteryRemoved(bool *out);
|
||||
Result GetTemperature(double *out);
|
||||
Result GetAverageVCell(u32 *out);
|
||||
Result GetSocRep(double *out);
|
||||
Result GetBatteryPercentage(size_t *out);
|
||||
Result SetShutdownTimer();
|
||||
Result GetShutdownEnabled(bool *out);
|
||||
Result SetShutdownEnabled(bool enabled);
|
||||
};
|
||||
34
stratosphere/boot/source/boot_battery_icon_charging.hpp
Normal file
34
stratosphere/boot/source/boot_battery_icon_charging.hpp
Normal file
File diff suppressed because one or more lines are too long
34
stratosphere/boot/source/boot_battery_icon_charging_red.hpp
Normal file
34
stratosphere/boot/source/boot_battery_icon_charging_red.hpp
Normal file
File diff suppressed because one or more lines are too long
28
stratosphere/boot/source/boot_battery_icon_low.hpp
Normal file
28
stratosphere/boot/source/boot_battery_icon_low.hpp
Normal file
File diff suppressed because one or more lines are too long
83
stratosphere/boot/source/boot_battery_icons.cpp
Normal file
83
stratosphere/boot/source/boot_battery_icons.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_battery_icon_low.hpp"
|
||||
#include "boot_battery_icon_charging.hpp"
|
||||
#include "boot_battery_icon_charging_red.hpp"
|
||||
|
||||
void Boot::ShowLowBatteryIcon() {
|
||||
Boot::InitializeDisplay();
|
||||
{
|
||||
/* Low battery icon is shown for 5 seconds. */
|
||||
Boot::ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
|
||||
svcSleepThread(5'000'000'000ul);
|
||||
}
|
||||
Boot::FinalizeDisplay();
|
||||
}
|
||||
|
||||
static void FillBatteryMeter(u32 *icon, const size_t icon_w, const size_t icon_h, const size_t meter_x, const size_t meter_y, const size_t meter_w, const size_t meter_h, const size_t fill_w) {
|
||||
const size_t fill_x = meter_x + meter_w - fill_w;
|
||||
|
||||
if (fill_x + fill_w > icon_w || meter_y + meter_h > icon_h || fill_x == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 *cur_row = icon + meter_y * icon_w + fill_x;
|
||||
for (size_t y = 0; y < meter_h; y++) {
|
||||
/* Make last column of meter identical to first column of meter. */
|
||||
cur_row[-1] = icon[(meter_y + y) * icon_w + meter_x];
|
||||
|
||||
/* Black out further pixels. */
|
||||
for (size_t x = 0; x < fill_w; x++) {
|
||||
cur_row[x] = 0xFF000000;
|
||||
}
|
||||
cur_row += icon_w;
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::StartShowChargingIcon(size_t battery_percentage, bool wait) {
|
||||
const bool is_red = battery_percentage <= 15;
|
||||
|
||||
const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX;
|
||||
const size_t IconY = is_red ? ChargingRedBatteryY : ChargingBatteryY;
|
||||
const size_t IconW = is_red ? ChargingRedBatteryW : ChargingBatteryW;
|
||||
const size_t IconH = is_red ? ChargingRedBatteryH : ChargingBatteryH;
|
||||
const size_t IconMeterX = is_red ? ChargingRedBatteryMeterX : ChargingBatteryMeterX;
|
||||
const size_t IconMeterY = is_red ? ChargingRedBatteryMeterY : ChargingBatteryMeterY;
|
||||
const size_t IconMeterW = is_red ? ChargingRedBatteryMeterW : ChargingBatteryMeterW;
|
||||
const size_t IconMeterH = is_red ? ChargingRedBatteryMeterH : ChargingBatteryMeterH;
|
||||
const size_t MeterFillW = static_cast<size_t>(IconMeterW * (1.0 - (0.0404 + 0.0096 * battery_percentage)) + 0.5);
|
||||
|
||||
/* Create stack buffer, copy icon into it, draw fill meter, draw. */
|
||||
{
|
||||
u32 Icon[IconW * IconH];
|
||||
std::memcpy(Icon, is_red ? ChargingRedBattery : ChargingBattery, sizeof(Icon));
|
||||
FillBatteryMeter(Icon, IconW, IconH, IconMeterX, IconMeterY, IconMeterW, IconMeterH, MeterFillW);
|
||||
|
||||
Boot::InitializeDisplay();
|
||||
Boot::ShowDisplay(IconX, IconY, IconW, IconH, Icon);
|
||||
}
|
||||
|
||||
/* Wait for 2 seconds if we're supposed to. */
|
||||
if (wait) {
|
||||
svcSleepThread(2'000'000'000ul);
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::EndShowChargingIcon() {
|
||||
Boot::FinalizeDisplay();
|
||||
}
|
||||
286
stratosphere/boot/source/boot_battery_parameters.hpp
Normal file
286
stratosphere/boot/source/boot_battery_parameters.hpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
static constexpr u8 Max17050Status = 0x00;
|
||||
static constexpr u8 Max17050VAlrtThreshold = 0x01;
|
||||
static constexpr u8 Max17050TAlrtThreshold = 0x02;
|
||||
static constexpr u8 Max17050SocAlrtThreshold = 0x03;
|
||||
static constexpr u8 Max17050AtRate = 0x04;
|
||||
static constexpr u8 Max17050RemCapRep = 0x05;
|
||||
static constexpr u8 Max17050SocRep = 0x06;
|
||||
static constexpr u8 Max17050Age = 0x07;
|
||||
static constexpr u8 Max17050Temperature = 0x08;
|
||||
static constexpr u8 Max17050VCell = 0x09;
|
||||
static constexpr u8 Max17050Current = 0x0A;
|
||||
static constexpr u8 Max17050AverageCurrent = 0x0B;
|
||||
|
||||
static constexpr u8 Max17050SocMix = 0x0D;
|
||||
static constexpr u8 Max17050SocAv = 0x0E;
|
||||
static constexpr u8 Max17050RemCapMix = 0x0F;
|
||||
static constexpr u8 Max17050FullCap = 0x10;
|
||||
static constexpr u8 Max17050Tte = 0x11;
|
||||
static constexpr u8 Max17050QResidual00 = 0x12;
|
||||
static constexpr u8 Max17050FullSocThr = 0x13;
|
||||
|
||||
|
||||
static constexpr u8 Max17050AverageTemp = 0x16;
|
||||
static constexpr u8 Max17050Cycles = 0x17;
|
||||
static constexpr u8 Max17050DesignCap = 0x18;
|
||||
static constexpr u8 Max17050AverageVCell = 0x19;
|
||||
static constexpr u8 Max17050MaxMinTemp = 0x1A;
|
||||
static constexpr u8 Max17050MaxMinVoltage = 0x1B;
|
||||
static constexpr u8 Max17050MaxMinCurrent = 0x1C;
|
||||
static constexpr u8 Max17050Config = 0x1D;
|
||||
static constexpr u8 Max17050IChgTerm = 0x1E;
|
||||
static constexpr u8 Max17050RemCapAv = 0x1F;
|
||||
|
||||
static constexpr u8 Max17050Version = 0x21;
|
||||
static constexpr u8 Max17050QResidual10 = 0x22;
|
||||
static constexpr u8 Max17050FullCapNom = 0x23;
|
||||
static constexpr u8 Max17050TempNom = 0x24;
|
||||
static constexpr u8 Max17050TempLim = 0x25;
|
||||
|
||||
static constexpr u8 Max17050Ain = 0x27;
|
||||
static constexpr u8 Max17050LearnCfg = 0x28;
|
||||
static constexpr u8 Max17050FilterCfg = 0x29;
|
||||
static constexpr u8 Max17050RelaxCfg = 0x2A;
|
||||
static constexpr u8 Max17050MiscCfg = 0x2B;
|
||||
static constexpr u8 Max17050TGain = 0x2C;
|
||||
static constexpr u8 Max17050TOff = 0x2D;
|
||||
static constexpr u8 Max17050CGain = 0x2E;
|
||||
static constexpr u8 Max17050COff = 0x2F;
|
||||
|
||||
|
||||
static constexpr u8 Max17050QResidual20 = 0x32;
|
||||
|
||||
|
||||
|
||||
static constexpr u8 Max17050IAvgEmpty = 0x36;
|
||||
static constexpr u8 Max17050FCtc = 0x37;
|
||||
static constexpr u8 Max17050RComp0 = 0x38;
|
||||
static constexpr u8 Max17050TempCo = 0x39;
|
||||
static constexpr u8 Max17050VEmpty = 0x3A;
|
||||
|
||||
|
||||
static constexpr u8 Max17050FStat = 0x3D;
|
||||
static constexpr u8 Max17050Timer = 0x3E;
|
||||
static constexpr u8 Max17050ShdnTimer = 0x3F;
|
||||
|
||||
|
||||
static constexpr u8 Max17050QResidual30 = 0x42;
|
||||
|
||||
|
||||
static constexpr u8 Max17050DQAcc = 0x45;
|
||||
static constexpr u8 Max17050DPAcc = 0x46;
|
||||
|
||||
static constexpr u8 Max17050SocVf0 = 0x48;
|
||||
|
||||
static constexpr u8 Max17050Qh0 = 0x4C;
|
||||
static constexpr u8 Max17050Qh = 0x4D;
|
||||
|
||||
static constexpr u8 Max17050SocVfAccess = 0x60;
|
||||
|
||||
static constexpr u8 Max17050ModelAccess0 = 0x62;
|
||||
static constexpr u8 Max17050ModelAccess1 = 0x63;
|
||||
|
||||
static constexpr u8 Max17050ModelChrTblStart = 0x80;
|
||||
static constexpr u8 Max17050ModelChrTblEnd = 0xB0;
|
||||
|
||||
|
||||
static constexpr u8 Max17050VFocV = 0xFB;
|
||||
static constexpr u8 Max17050SocVf = 0xFF;
|
||||
|
||||
static constexpr size_t Max17050ModelChrTblSize = Max17050ModelChrTblEnd - Max17050ModelChrTblStart;
|
||||
|
||||
struct Max17050Parameters {
|
||||
u16 relaxcfg;
|
||||
u16 rcomp0;
|
||||
u16 tempco;
|
||||
u16 ichgterm;
|
||||
u16 tgain;
|
||||
u16 toff;
|
||||
u16 vempty;
|
||||
u16 qresidual00;
|
||||
u16 qresidual10;
|
||||
u16 qresidual20;
|
||||
u16 qresidual30;
|
||||
u16 fullcap;
|
||||
u16 vffullcap;
|
||||
u16 modeltbl[Max17050ModelChrTblSize];
|
||||
u16 fullsocthr;
|
||||
u16 iavgempty;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Max17050Parameters) == 0x7E, "Max17050Parameters definition!");
|
||||
|
||||
static constexpr Max17050Parameters Max17050ParamsA = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x0053, /* rcomp0 */
|
||||
0x1C22, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x5786, /* qresidual00 */
|
||||
0x3184, /* qresidual10 */
|
||||
0x1E00, /* qresidual20 */
|
||||
0x1602, /* qresidual30 */
|
||||
0x2476, /* fullcap */
|
||||
0x2476, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0x9FF0, 0xAD30, 0xB5D0, 0xB9C0, 0xBAD0, 0xBBE0, 0xBC30, 0xBC90,
|
||||
0xBCE0, 0xBD40, 0xBE70, 0xC0E0, 0xC4E0, 0xC890, 0xCC90, 0xD0F0,
|
||||
0x0170, 0x0480, 0x0590, 0x0BE0, 0x0A00, 0x3C00, 0x3810, 0x3A00,
|
||||
0x3A30, 0x19F0, 0x0EF0, 0x0AF0, 0x0BD0, 0x07F0, 0x06F0, 0x06F0,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
0x5F00, /* fullsocthr */
|
||||
0x1D2A /* iavgempty */
|
||||
};
|
||||
|
||||
static constexpr Max17050Parameters Max17050ParamsM = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x0085, /* rcomp0 */
|
||||
0x1625, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x3100, /* qresidual00 */
|
||||
0x1B00, /* qresidual10 */
|
||||
0x1000, /* qresidual20 */
|
||||
0x0C81, /* qresidual30 */
|
||||
0x227A, /* fullcap */
|
||||
0x227A, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0xA340, 0xB840, 0xB900, 0xBB70, 0xBC90, 0xBD20, 0xBDC0, 0xBEA0,
|
||||
0xBF70, 0xC030, 0xC210, 0xC3F0, 0xC800, 0xC9E0, 0xCCA0, 0xD090,
|
||||
0x0160, 0x3800, 0x0800, 0x1E00, 0x2550, 0x3060, 0x15D0, 0x1810,
|
||||
0x1490, 0x0B80, 0x0BF0, 0x0AF0, 0x0CB0, 0x06F0, 0x09D0, 0x09D0,
|
||||
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
|
||||
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
|
||||
},
|
||||
0x5F00, /* fullsocthr */
|
||||
0x1D2A /* iavgempty */
|
||||
};
|
||||
|
||||
static constexpr Max17050Parameters Max17050ParamsR = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x0048, /* rcomp0 */
|
||||
0x2034, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x5A00, /* qresidual00 */
|
||||
0x3B00, /* qresidual10 */
|
||||
0x0F80, /* qresidual20 */
|
||||
0x0B02, /* qresidual30 */
|
||||
0x2466, /* fullcap */
|
||||
0x2466, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0x9C50, 0xAD90, 0xB270, 0xB6A0, 0xB8F0, 0xBB10, 0xBC00, 0xBD00,
|
||||
0xBD70, 0xBE70, 0xBF50, 0xC1F0, 0xC380, 0xC590, 0xC8E0, 0xD0B0,
|
||||
0x00D0, 0x0150, 0x0300, 0x0D00, 0x0E00, 0x1900, 0x2AC0, 0x2830,
|
||||
0x1760, 0x18F0, 0x0DF0, 0x0BC0, 0x0DF0, 0x0BF0, 0x06F0, 0x06F0,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
0x5F00, /* fullsocthr */
|
||||
0x1D2A /* iavgempty */
|
||||
};
|
||||
|
||||
static constexpr Max17050Parameters Max17050Params1 = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x0040, /* rcomp0 */
|
||||
0x1624, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x4690, /* qresidual00 */
|
||||
0x2605, /* qresidual10 */
|
||||
0x1605, /* qresidual20 */
|
||||
0x0F05, /* qresidual30 */
|
||||
0x1AE4, /* fullcap */
|
||||
0x1AE4, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0x8B50, 0x9C20, 0xACF0, 0xB160, 0xB3A0, 0xB5B0, 0xB950, 0xBBE0,
|
||||
0xBDC0, 0xBEF0, 0xC140, 0xC250, 0xC600, 0xC960, 0xCCE0, 0xD060,
|
||||
0x0070, 0x00F0, 0x0440, 0x0400, 0x0500, 0x0400, 0x0D00, 0x3270,
|
||||
0x0FB0, 0x0AF0, 0x10F0, 0x0CE0, 0x09E0, 0x07F0, 0x06F0, 0x06F0,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
0x5F00, /* fullsocthr */
|
||||
0x1584 /* iavgempty */
|
||||
};
|
||||
|
||||
static constexpr Max17050Parameters Max17050Params2 = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x004A, /* rcomp0 */
|
||||
0x1D23, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x4000, /* qresidual00 */
|
||||
0x1E80, /* qresidual10 */
|
||||
0x0D83, /* qresidual20 */
|
||||
0x0783, /* qresidual30 */
|
||||
0x1C20, /* fullcap */
|
||||
0x1C20, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0x8040, 0x9A30, 0xB430, 0xB770, 0xBAB0, 0xBBC0, 0xBD00, 0xBE50,
|
||||
0xBF70, 0xC0D0, 0xC300, 0xC590, 0xC960, 0xCD40, 0xD1F0, 0xD5C0,
|
||||
0x0040, 0x0060, 0x0510, 0x0D30, 0x16C0, 0x2160, 0x1380, 0x1A10,
|
||||
0x0EC0, 0x0CE0, 0x08F0, 0x0940, 0x0920, 0x06F0, 0x06C0, 0x06C0,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
0x5500, /* fullsocthr */
|
||||
0x1680 /* iavgempty */
|
||||
};
|
||||
|
||||
static constexpr Max17050Parameters Max17050Params2M = {
|
||||
0x203B, /* relaxcfg */
|
||||
0x0049, /* rcomp0 */
|
||||
0x222A, /* tempco */
|
||||
0x0333, /* ichgterm */
|
||||
0xE1F6, /* tgain */
|
||||
0x2BF2, /* toff */
|
||||
0xA05F, /* vempty */
|
||||
0x4F00, /* qresidual00 */
|
||||
0x2680, /* qresidual10 */
|
||||
0x1205, /* qresidual20 */
|
||||
0x0C87, /* qresidual30 */
|
||||
0x1C68, /* fullcap */
|
||||
0x1C68, /* vffullcap */
|
||||
{ /* modeltbl */
|
||||
0x8E40, 0xB570, 0xB8F0, 0xBB00, 0xBC20, 0xBCC0, 0xBE30, 0xBFE0,
|
||||
0xC200, 0xC400, 0xC720, 0xCB50, 0xCF00, 0xD100, 0xD480, 0xD5C0,
|
||||
0x00C0, 0x0C00, 0x0A10, 0x1800, 0x2C00, 0x1C10, 0x12D0, 0x09F0,
|
||||
0x0AF0, 0x0850, 0x09F0, 0x06F0, 0x06B0, 0x07E0, 0x01D0, 0x01D0,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||
},
|
||||
0x5500, /* fullsocthr */
|
||||
0x16B9 /* iavgempty */
|
||||
};
|
||||
113
stratosphere/boot/source/boot_boot_reason.cpp
Normal file
113
stratosphere/boot/source/boot_boot_reason.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_pmic_driver.hpp"
|
||||
#include "boot_rtc_driver.hpp"
|
||||
|
||||
static u32 g_boot_reason = 0;
|
||||
static bool g_detected_boot_reason = false;
|
||||
|
||||
struct BootReasonValue {
|
||||
union {
|
||||
struct {
|
||||
u8 power_intr;
|
||||
u8 rtc_intr;
|
||||
u8 nv_erc;
|
||||
u8 boot_reason;
|
||||
};
|
||||
u32 value;
|
||||
};
|
||||
};
|
||||
|
||||
static u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
|
||||
if (power_intr & 0x08) {
|
||||
return 2;
|
||||
}
|
||||
if (rtc_intr & 0x02) {
|
||||
return 3;
|
||||
}
|
||||
if (power_intr & 0x80) {
|
||||
return 1;
|
||||
}
|
||||
if (rtc_intr & 0x04) {
|
||||
if (nv_erc != 0x80 && !Boot::IsRecoveryBoot()) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
if ((nv_erc & 0x40) && ac_ok) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Boot::DetectBootReason() {
|
||||
u8 power_intr;
|
||||
u8 rtc_intr;
|
||||
u8 rtc_intr_m;
|
||||
u8 nv_erc;
|
||||
bool ac_ok;
|
||||
|
||||
/* Get values from PMIC. */
|
||||
{
|
||||
PmicDriver pmic_driver;
|
||||
if (R_FAILED(pmic_driver.GetPowerIntr(&power_intr))) {
|
||||
std::abort();
|
||||
}
|
||||
if (R_FAILED(pmic_driver.GetNvErc(&nv_erc))) {
|
||||
std::abort();
|
||||
}
|
||||
if (R_FAILED(pmic_driver.GetAcOk(&ac_ok))) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Get values from RTC. */
|
||||
{
|
||||
RtcDriver rtc_driver;
|
||||
if (R_FAILED(rtc_driver.GetRtcIntr(&rtc_intr))) {
|
||||
std::abort();
|
||||
}
|
||||
if (R_FAILED(rtc_driver.GetRtcIntrM(&rtc_intr_m))) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set global derived boot reason. */
|
||||
g_boot_reason = MakeBootReason(power_intr, rtc_intr & ~rtc_intr_m, nv_erc, ac_ok);
|
||||
|
||||
/* Set boot reason for SPL. */
|
||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_300) {
|
||||
BootReasonValue boot_reason_value;
|
||||
boot_reason_value.power_intr = power_intr;
|
||||
boot_reason_value.rtc_intr = rtc_intr & ~rtc_intr_m;
|
||||
boot_reason_value.nv_erc = nv_erc;
|
||||
boot_reason_value.boot_reason = g_boot_reason;
|
||||
if (R_FAILED(splSetBootReason(boot_reason_value.value))) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
g_detected_boot_reason = true;
|
||||
}
|
||||
|
||||
u32 Boot::GetBootReason() {
|
||||
if (!g_detected_boot_reason) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return g_boot_reason;
|
||||
}
|
||||
139
stratosphere/boot/source/boot_bq24193_charger.hpp
Normal file
139
stratosphere/boot/source/boot_bq24193_charger.hpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
static constexpr u8 Bq24193InputSourceControl = 0x00;
|
||||
static constexpr u8 Bq24193PowerOnConfiguration = 0x01;
|
||||
static constexpr u8 Bq24193ChargeCurrentControl = 0x02;
|
||||
static constexpr u8 Bq24193PreChargeTerminationCurrentControl = 0x03;
|
||||
static constexpr u8 Bq24193ChargeVoltageControl = 0x04;
|
||||
static constexpr u8 Bq24193ChargeTerminationTimerControl = 0x05;
|
||||
static constexpr u8 Bq24193IrCompensationThermalRegulationControl = 0x06;
|
||||
static constexpr u8 Bq24193MiscOperationControl = 0x07;
|
||||
static constexpr u8 Bq24193SystemStatus = 0x08;
|
||||
static constexpr u8 Bq24193Fault = 0x09;
|
||||
static constexpr u8 Bq24193VendorPartRevisionStatus = 0x0A;
|
||||
|
||||
enum ChargerConfiguration : u8 {
|
||||
ChargerConfiguration_ChargeDisable = (0 << 4),
|
||||
ChargerConfiguration_ChargeBattery = (1 << 4),
|
||||
ChargerConfiguration_Otg = (2 << 4),
|
||||
};
|
||||
|
||||
static constexpr u32 ChargeVoltageLimitMin = 3504;
|
||||
static constexpr u32 ChargeVoltageLimitMax = 4208;
|
||||
|
||||
static inline u8 EncodeChargeVoltageLimit(u32 voltage) {
|
||||
if (voltage < ChargeVoltageLimitMin || voltage > ChargeVoltageLimitMax) {
|
||||
std::abort();
|
||||
}
|
||||
voltage -= ChargeVoltageLimitMin;
|
||||
voltage >>= 4;
|
||||
return static_cast<u8>(voltage << 2);
|
||||
}
|
||||
|
||||
static inline u32 DecodeChargeVoltageLimit(u8 reg) {
|
||||
return ChargeVoltageLimitMin + (static_cast<u32>(reg & 0xFC) << 2);
|
||||
}
|
||||
|
||||
static constexpr u32 FastChargeCurrentLimitMin = 512;
|
||||
static constexpr u32 FastChargeCurrentLimitMax = 4544;
|
||||
|
||||
static inline u8 EncodeFastChargeCurrentLimit(u32 current) {
|
||||
if (current < FastChargeCurrentLimitMin || current > FastChargeCurrentLimitMax) {
|
||||
std::abort();
|
||||
}
|
||||
current -= FastChargeCurrentLimitMin;
|
||||
current >>= 6;
|
||||
return static_cast<u8>(current << 2);
|
||||
}
|
||||
|
||||
static inline u32 DecodeFastChargeCurrentLimit(u8 reg) {
|
||||
return FastChargeCurrentLimitMin + (static_cast<u32>(reg & 0xFC) << 4);
|
||||
}
|
||||
|
||||
enum InputCurrentLimit : u8 {
|
||||
InputCurrentLimit_100mA = 0,
|
||||
InputCurrentLimit_150mA = 1,
|
||||
InputCurrentLimit_500mA = 2,
|
||||
InputCurrentLimit_900mA = 3,
|
||||
InputCurrentLimit_1200mA = 4,
|
||||
InputCurrentLimit_1500mA = 5,
|
||||
InputCurrentLimit_2000mA = 6,
|
||||
InputCurrentLimit_3000mA = 7,
|
||||
};
|
||||
|
||||
static constexpr u32 PreChargeCurrentLimitMin = 128;
|
||||
static constexpr u32 PreChargeCurrentLimitMax = 2048;
|
||||
|
||||
static inline u8 EncodePreChargeCurrentLimit(u32 current) {
|
||||
if (current < PreChargeCurrentLimitMin || current > PreChargeCurrentLimitMax) {
|
||||
std::abort();
|
||||
}
|
||||
current -= PreChargeCurrentLimitMin;
|
||||
current >>= 7;
|
||||
return static_cast<u8>(current << 4);
|
||||
}
|
||||
|
||||
static inline u32 DecodePreChargeCurrentLimit(u8 reg) {
|
||||
return PreChargeCurrentLimitMin + (static_cast<u32>(reg & 0xF0) << 3);
|
||||
}
|
||||
|
||||
static constexpr u32 TerminationCurrentLimitMin = 128;
|
||||
static constexpr u32 TerminationCurrentLimitMax = 2048;
|
||||
|
||||
static inline u8 EncodeTerminationCurrentLimit(u32 current) {
|
||||
if (current < TerminationCurrentLimitMin || current > TerminationCurrentLimitMax) {
|
||||
std::abort();
|
||||
}
|
||||
current -= TerminationCurrentLimitMin;
|
||||
current >>= 7;
|
||||
return static_cast<u8>(current);
|
||||
}
|
||||
|
||||
static inline u32 DecodeTerminationCurrentLimit(u8 reg) {
|
||||
return TerminationCurrentLimitMin + (static_cast<u32>(reg & 0xF) << 7);
|
||||
}
|
||||
|
||||
static constexpr u32 MinimumSystemVoltageLimitMin = 3000;
|
||||
static constexpr u32 MinimumSystemVoltageLimitMax = 3700;
|
||||
|
||||
static inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) {
|
||||
if (voltage < MinimumSystemVoltageLimitMin || voltage > MinimumSystemVoltageLimitMax) {
|
||||
std::abort();
|
||||
}
|
||||
voltage -= MinimumSystemVoltageLimitMin;
|
||||
voltage /= 100;
|
||||
return static_cast<u8>(voltage << 1);
|
||||
}
|
||||
|
||||
static inline u32 DecodeMinimumSystemVoltageLimit(u8 reg) {
|
||||
return MinimumSystemVoltageLimitMin + (static_cast<u32>(reg & 0x0E) * 50);
|
||||
}
|
||||
|
||||
enum WatchdogTimerSetting : u8 {
|
||||
WatchdogTimerSetting_Disabled = (0 << 4),
|
||||
WatchdogTimerSetting_40s = (1 << 4),
|
||||
WatchdogTimerSetting_80s = (2 << 4),
|
||||
WatchdogTimerSetting_160s = (3 << 4),
|
||||
};
|
||||
|
||||
enum BoostModeCurrentLimit : u8 {
|
||||
BoostModeCurrentLimit_500mA = 0,
|
||||
BoostModeCurrentLimit_1300mA = 1,
|
||||
};
|
||||
114
stratosphere/boot/source/boot_calibration.cpp
Normal file
114
stratosphere/boot/source/boot_calibration.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
|
||||
static constexpr size_t BatteryLotOffset = 0x2CE0;
|
||||
static constexpr size_t BatteryLotSize = 0x20;
|
||||
static constexpr size_t BatteryVersionOffset = 0x4310;
|
||||
static constexpr size_t BatteryVersionSize = 0x10;
|
||||
|
||||
static constexpr u32 BisStorageId_Prodinfo = 27;
|
||||
|
||||
static constexpr u32 DefaultBatteryVendor = static_cast<u32>('A');
|
||||
static constexpr u32 DefaultBatteryVersion = 0;
|
||||
|
||||
static constexpr Result ResultCalInvalidCrc = 0xCAC6; /* TODO: Verify this really is cal, move to libstrat results. */
|
||||
|
||||
u16 Boot::GetCrc16(const void *data, size_t size) {
|
||||
static constexpr u16 s_crc_table[0x10] = {
|
||||
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
||||
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
||||
};
|
||||
|
||||
if (data == nullptr) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
u16 crc16 = 0x55AA;
|
||||
const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[data_u8[i] & 0xF]);
|
||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[(data_u8[i] >> 4) & 0xF]);
|
||||
}
|
||||
return crc16;
|
||||
}
|
||||
|
||||
static Result ValidateCalibrationCrc16(const void *data, size_t size) {
|
||||
const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
|
||||
if (Boot::GetCrc16(data, size - sizeof(u16)) != *(reinterpret_cast<const u16 *>(&data_u8[size - sizeof(u16)]))) {
|
||||
return ResultCalInvalidCrc;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static Result GetBatteryVendorImpl(u32 *vendor) {
|
||||
FsStorage s;
|
||||
Result rc = fsOpenBisStorage(&s, BisStorageId_Prodinfo);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
ON_SCOPE_EXIT { fsStorageClose(&s); };
|
||||
|
||||
u8 battery_lot[BatteryLotSize];
|
||||
if (R_FAILED((rc = fsStorageRead(&s, BatteryLotOffset, battery_lot, sizeof(battery_lot))))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = ValidateCalibrationCrc16(battery_lot, sizeof(battery_lot))))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
*vendor = battery_lot[7];
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static Result GetBatteryVersionImpl(u32 *version) {
|
||||
FsStorage s;
|
||||
Result rc = fsOpenBisStorage(&s, BisStorageId_Prodinfo);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
ON_SCOPE_EXIT { fsStorageClose(&s); };
|
||||
|
||||
u8 battery_version[BatteryVersionSize];
|
||||
if (R_FAILED((rc = fsStorageRead(&s, BatteryVersionOffset, battery_version, sizeof(battery_version))))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = ValidateCalibrationCrc16(battery_version, sizeof(battery_version))))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
*version = battery_version[0];
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
u32 Boot::GetBatteryVendor() {
|
||||
u32 vendor;
|
||||
if (R_FAILED(GetBatteryVendorImpl(&vendor))) {
|
||||
return DefaultBatteryVendor;
|
||||
}
|
||||
return vendor;
|
||||
}
|
||||
|
||||
u32 Boot::GetBatteryVersion() {
|
||||
u32 version;
|
||||
if (R_FAILED(GetBatteryVersionImpl(&version))) {
|
||||
return DefaultBatteryVersion;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
36
stratosphere/boot/source/boot_change_voltage.cpp
Normal file
36
stratosphere/boot/source/boot_change_voltage.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
|
||||
static constexpr u32 Sdmmc3VoltageBit = (1 << 13); /* SDMMC3 */
|
||||
static constexpr u32 AudioVoltageBit = (1 << 18); /* AUDIO_HV */
|
||||
static constexpr u32 GpioVoltageBit = (1 << 21); /* GPIO */
|
||||
static constexpr u32 SpiVoltageBit = (1 << 23); /* SPI_HV */
|
||||
|
||||
static constexpr u32 VoltageChangeMask = SpiVoltageBit | GpioVoltageBit | AudioVoltageBit | Sdmmc3VoltageBit;
|
||||
|
||||
static constexpr u32 PmcPwrDet = 0x7000E448;
|
||||
static constexpr u32 PmcPwrDetVal = 0x7000E4E4;
|
||||
|
||||
void Boot::ChangeGpioVoltageTo1_8v() {
|
||||
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
||||
WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask);
|
||||
WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask);
|
||||
|
||||
/* Sleep for 100 us. */
|
||||
svcSleepThread(100'000ul);
|
||||
}
|
||||
177
stratosphere/boot/source/boot_charger_driver.cpp
Normal file
177
stratosphere/boot/source/boot_charger_driver.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_charger_driver.hpp"
|
||||
|
||||
Result ChargerDriver::Read(u8 addr, u8 *out) {
|
||||
return Boot::ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
Result ChargerDriver::Write(u8 addr, u8 val) {
|
||||
return Boot::WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
Result ChargerDriver::ReadWrite(u8 addr, u8 mask, u8 val) {
|
||||
Result rc;
|
||||
u8 cur_val;
|
||||
if (R_FAILED((rc = this->Read(addr, &cur_val)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
const u8 new_val = (cur_val & ~mask) | val;
|
||||
if (R_FAILED((rc = this->Write(addr, new_val)))) {
|
||||
return rc;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ChargerDriver::Initialize() {
|
||||
return this->Initialize(true);
|
||||
}
|
||||
|
||||
Result ChargerDriver::Initialize(bool set_input_current_limit) {
|
||||
Result rc;
|
||||
if (set_input_current_limit) {
|
||||
if (R_FAILED((rc = this->SetInputCurrentLimit(InputCurrentLimit_500mA)))) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetChargeVoltageLimit(4208)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetFastChargeCurrentLimit(512)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetForce20PercentChargeCurrent(false)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetPreChargeCurrentLimit(128)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetTerminationCurrentLimit(128)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetMinimumSystemVoltageLimit(3000)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetWatchdogTimerSetting(WatchdogTimerSetting_Disabled)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetChargingSafetyTimerEnabled(false)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->ResetWatchdogTimer()))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetBoostModeCurrentLimit(BoostModeCurrentLimit_500mA)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = this->SetHiZEnabled(false)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetChargeEnabled(bool enabled) {
|
||||
Boot::GpioSetValue(GpioPadName_Bq24193Charger, enabled ? GpioValue_Low : GpioValue_High);
|
||||
return this->SetChargerConfiguration(ChargerConfiguration_ChargeBattery);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetChargerConfiguration(ChargerConfiguration config) {
|
||||
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x30, config);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetChargeVoltageLimit(u32 voltage) {
|
||||
return this->ReadWrite(Bq24193ChargeVoltageControl, 0xFC, EncodeChargeVoltageLimit(voltage));
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetFastChargeCurrentLimit(u32 current) {
|
||||
return this->ReadWrite(Bq24193ChargeCurrentControl, 0xFC, EncodeFastChargeCurrentLimit(current));
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetInputCurrentLimit(InputCurrentLimit current) {
|
||||
return this->ReadWrite(Bq24193InputSourceControl, 0x07, current);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetForce20PercentChargeCurrent(bool force) {
|
||||
return this->ReadWrite(Bq24193ChargeCurrentControl, 0x01, force ? 1 : 0);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetPreChargeCurrentLimit(u32 current) {
|
||||
return this->ReadWrite(Bq24193PreChargeTerminationCurrentControl, 0xF0, EncodePreChargeCurrentLimit(current));
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetTerminationCurrentLimit(u32 current) {
|
||||
return this->ReadWrite(Bq24193PreChargeTerminationCurrentControl, 0x0F, EncodeTerminationCurrentLimit(current));
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetMinimumSystemVoltageLimit(u32 voltage) {
|
||||
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x0E, EncodeMinimumSystemVoltageLimit(voltage));
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetWatchdogTimerSetting(WatchdogTimerSetting setting) {
|
||||
return this->ReadWrite(Bq24193ChargeTerminationTimerControl, 0x30, setting);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetChargingSafetyTimerEnabled(bool enabled) {
|
||||
return this->ReadWrite(Bq24193ChargeTerminationTimerControl, 0x08, enabled ? 0x08 : 0);
|
||||
}
|
||||
|
||||
Result ChargerDriver::ResetWatchdogTimer() {
|
||||
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x40, 0x40);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetBoostModeCurrentLimit(BoostModeCurrentLimit current) {
|
||||
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x01, current);
|
||||
}
|
||||
|
||||
Result ChargerDriver::SetHiZEnabled(bool enabled) {
|
||||
return this->ReadWrite(Bq24193InputSourceControl, 0x80, enabled ? 0x80 : 0);
|
||||
}
|
||||
|
||||
Result ChargerDriver::GetInputCurrentLimit(InputCurrentLimit *out) {
|
||||
u8 limit;
|
||||
Result rc = this->Read(Bq24193InputSourceControl, &limit);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = static_cast<InputCurrentLimit>(limit);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ChargerDriver::GetChargeVoltageLimit(u32 *out) {
|
||||
u8 reg;
|
||||
Result rc = this->Read(Bq24193ChargeVoltageControl, ®);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
*out = DecodeChargeVoltageLimit(reg);
|
||||
return ResultSuccess;
|
||||
}
|
||||
67
stratosphere/boot/source/boot_charger_driver.hpp
Normal file
67
stratosphere/boot/source/boot_charger_driver.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "i2c_driver/i2c_api.hpp"
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_bq24193_charger.hpp"
|
||||
|
||||
class ChargerDriver {
|
||||
private:
|
||||
static constexpr u32 GpioPadName_Bq24193Charger = 0xA;
|
||||
private:
|
||||
I2cSessionImpl i2c_session;
|
||||
public:
|
||||
ChargerDriver() {
|
||||
I2cDriver::Initialize();
|
||||
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Bq24193);
|
||||
|
||||
Boot::GpioSetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output);
|
||||
}
|
||||
|
||||
~ChargerDriver() {
|
||||
I2cDriver::CloseSession(this->i2c_session);
|
||||
I2cDriver::Finalize();
|
||||
}
|
||||
private:
|
||||
Result Read(u8 addr, u8 *out_data);
|
||||
Result Write(u8 addr, u8 val);
|
||||
Result ReadWrite(u8 addr, u8 mask, u8 val);
|
||||
|
||||
Result SetInputCurrentLimit(InputCurrentLimit current);
|
||||
Result SetForce20PercentChargeCurrent(bool force);
|
||||
Result SetPreChargeCurrentLimit(u32 current);
|
||||
Result SetTerminationCurrentLimit(u32 current);
|
||||
Result SetMinimumSystemVoltageLimit(u32 voltage);
|
||||
Result SetWatchdogTimerSetting(WatchdogTimerSetting setting);
|
||||
Result SetChargingSafetyTimerEnabled(bool enabled);
|
||||
Result ResetWatchdogTimer();
|
||||
Result SetBoostModeCurrentLimit(BoostModeCurrentLimit current);
|
||||
Result SetHiZEnabled(bool enabled);
|
||||
|
||||
public:
|
||||
Result Initialize();
|
||||
Result Initialize(bool set_input_current_limit);
|
||||
Result SetChargeVoltageLimit(u32 voltage);
|
||||
Result SetFastChargeCurrentLimit(u32 current);
|
||||
Result SetChargeEnabled(bool enabled);
|
||||
Result SetChargerConfiguration(ChargerConfiguration config);
|
||||
Result GetInputCurrentLimit(InputCurrentLimit *out);
|
||||
Result GetChargeVoltageLimit(u32 *out);
|
||||
};
|
||||
275
stratosphere/boot/source/boot_check_battery.cpp
Normal file
275
stratosphere/boot/source/boot_check_battery.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_pmic_driver.hpp"
|
||||
#include "boot_battery_driver.hpp"
|
||||
#include "boot_charger_driver.hpp"
|
||||
|
||||
enum CheckBatteryResult {
|
||||
CheckBatteryResult_Success = 0,
|
||||
CheckBatteryResult_Shutdown = 1,
|
||||
CheckBatteryResult_Reboot = 2,
|
||||
};
|
||||
|
||||
struct BatteryChargeParameters {
|
||||
u32 temp_min;
|
||||
u32 temp_low;
|
||||
u32 temp_high;
|
||||
u32 temp_max;
|
||||
u32 allow_high_temp_charge_max_voltage;
|
||||
u32 charge_voltage_limit_default;
|
||||
u32 charge_voltage_limit_high_temp;
|
||||
u32 allow_fast_charge_min_temp;
|
||||
u32 allow_fast_charge_min_voltage;
|
||||
u32 fast_charge_current_limit_default;
|
||||
u32 fast_charge_current_limit_low_temp;
|
||||
u32 fast_charge_current_limit_low_voltage;
|
||||
};
|
||||
|
||||
static constexpr BatteryChargeParameters BatteryChargeParameters0 = {
|
||||
.temp_min = 4,
|
||||
.temp_low = 17,
|
||||
.temp_high = 51,
|
||||
.temp_max = 60,
|
||||
.allow_high_temp_charge_max_voltage = 4050,
|
||||
.charge_voltage_limit_default = 4208,
|
||||
.charge_voltage_limit_high_temp = 3952,
|
||||
.allow_fast_charge_min_voltage = 3320,
|
||||
.fast_charge_current_limit_default = 0x800,
|
||||
.fast_charge_current_limit_low_temp = 0x300,
|
||||
.fast_charge_current_limit_low_voltage = 0x200,
|
||||
};
|
||||
|
||||
static constexpr BatteryChargeParameters BatteryChargeParameters1 = {
|
||||
.temp_min = 4,
|
||||
.temp_low = 17,
|
||||
.temp_high = 51,
|
||||
.temp_max = 59,
|
||||
.allow_high_temp_charge_max_voltage = 3984,
|
||||
.charge_voltage_limit_default = 4208,
|
||||
.charge_voltage_limit_high_temp = 3984,
|
||||
.allow_fast_charge_min_voltage = 0,
|
||||
.fast_charge_current_limit_default = 0x600,
|
||||
.fast_charge_current_limit_low_temp = 0x240,
|
||||
.fast_charge_current_limit_low_voltage = 0x600,
|
||||
};
|
||||
|
||||
static constexpr BatteryChargeParameters BatteryChargeParameters2 = {
|
||||
.temp_min = 4,
|
||||
.temp_low = 17,
|
||||
.temp_high = 51,
|
||||
.temp_max = 59,
|
||||
.allow_high_temp_charge_max_voltage = 4080,
|
||||
.charge_voltage_limit_default = 4320,
|
||||
.charge_voltage_limit_high_temp = 4080,
|
||||
.allow_fast_charge_min_voltage = 0,
|
||||
.fast_charge_current_limit_default = 0x680,
|
||||
.fast_charge_current_limit_low_temp = 0x280,
|
||||
.fast_charge_current_limit_low_voltage = 0x680,
|
||||
};
|
||||
|
||||
static const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_version) {
|
||||
switch (battery_version) {
|
||||
case 0:
|
||||
return &BatteryChargeParameters0;
|
||||
case 1:
|
||||
return &BatteryChargeParameters1;
|
||||
case 2:
|
||||
return &BatteryChargeParameters2;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateCharger(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit) {
|
||||
double temperature;
|
||||
u32 battery_voltage;
|
||||
|
||||
if (R_FAILED(battery_driver->GetTemperature(&temperature)) || R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) {
|
||||
pmic_driver->ShutdownSystem();
|
||||
}
|
||||
|
||||
bool enable_charge = true;
|
||||
if (temperature < double(params->temp_min)) {
|
||||
enable_charge = false;
|
||||
} else if (double(params->temp_high) <= temperature && temperature < double(params->temp_max)) {
|
||||
if (battery_voltage < params->allow_high_temp_charge_max_voltage) {
|
||||
charge_voltage_limit = std::min(charge_voltage_limit, params->charge_voltage_limit_high_temp);
|
||||
} else {
|
||||
enable_charge = false;
|
||||
}
|
||||
} else if (double(params->temp_max) <= temperature) {
|
||||
enable_charge = false;
|
||||
if (battery_voltage < params->allow_high_temp_charge_max_voltage) {
|
||||
charge_voltage_limit = std::min(charge_voltage_limit, params->charge_voltage_limit_high_temp);
|
||||
}
|
||||
}
|
||||
|
||||
u32 fast_charge_current_limit = params->fast_charge_current_limit_default;
|
||||
if (temperature < double(params->temp_low)) {
|
||||
fast_charge_current_limit = std::min(fast_charge_current_limit, params->fast_charge_current_limit_low_temp);
|
||||
}
|
||||
if (battery_voltage < params->allow_fast_charge_min_voltage) {
|
||||
fast_charge_current_limit = std::min(fast_charge_current_limit, params->fast_charge_current_limit_low_voltage);
|
||||
}
|
||||
|
||||
if (R_FAILED(charger_driver->SetChargeEnabled(enable_charge))) {
|
||||
pmic_driver->ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(charger_driver->SetChargeVoltageLimit(charge_voltage_limit))) {
|
||||
pmic_driver->ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(charger_driver->SetFastChargeCurrentLimit(fast_charge_current_limit))) {
|
||||
pmic_driver->ShutdownSystem();
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSufficientBattery(u32 battery_voltage, bool ac_ok) {
|
||||
/* Nintendo has stuff for updating a static variable every 10 seconds here, but this seems, again, to be debug leftovers. */
|
||||
const u32 required_voltage = ac_ok ? 4000 : 3650;
|
||||
return battery_voltage >= required_voltage;
|
||||
}
|
||||
|
||||
static CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit, bool reboot_on_power_button_pressed, bool succeed_on_sufficient_battery, bool shutdown_on_full_battery, bool can_show_battery_icon, bool can_show_charging_icon) {
|
||||
bool is_showing_charging_icon = false;
|
||||
ON_SCOPE_EXIT {
|
||||
if (is_showing_charging_icon) {
|
||||
Boot::EndShowChargingIcon();
|
||||
}
|
||||
};
|
||||
|
||||
if (can_show_charging_icon) {
|
||||
size_t battery_percentage;
|
||||
if (R_FAILED(battery_driver->GetBatteryPercentage(&battery_percentage))) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
Boot::StartShowChargingIcon(battery_percentage, true);
|
||||
is_showing_charging_icon = true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
double battery_charge;
|
||||
if (R_FAILED(battery_driver->GetSocRep(&battery_charge))) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
if (succeed_on_sufficient_battery && battery_charge >= 3.0) {
|
||||
return CheckBatteryResult_Success;
|
||||
} else if (shutdown_on_full_battery && battery_charge >= 99.0) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
} else {
|
||||
/* Nintendo has logic for checking a value every 10 seconds. */
|
||||
/* They never do anything with this value though, so it's probably just leftovers from debug? */
|
||||
}
|
||||
|
||||
bool ac_ok;
|
||||
if (R_FAILED(pmic_driver->GetAcOk(&ac_ok))) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
|
||||
u32 battery_voltage;
|
||||
if (R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
|
||||
if (succeed_on_sufficient_battery && IsSufficientBattery(battery_voltage, ac_ok)) {
|
||||
return CheckBatteryResult_Success;
|
||||
}
|
||||
|
||||
if (!ac_ok) {
|
||||
if (can_show_battery_icon && !is_showing_charging_icon) {
|
||||
Boot::ShowLowBatteryIcon();
|
||||
}
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
|
||||
if (reboot_on_power_button_pressed) {
|
||||
bool power_button_pressed;
|
||||
if (R_FAILED(pmic_driver->GetPowerButtonPressed(&power_button_pressed))) {
|
||||
return CheckBatteryResult_Shutdown;
|
||||
}
|
||||
if (power_button_pressed) {
|
||||
return CheckBatteryResult_Reboot;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_show_battery_icon && !is_showing_charging_icon) {
|
||||
Boot::StartShowChargingIcon(1, false);
|
||||
is_showing_charging_icon = true;
|
||||
}
|
||||
|
||||
svcSleepThread(20'000'000ul);
|
||||
UpdateCharger(pmic_driver, charger_driver, battery_driver, params, charge_voltage_limit);
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::CheckBatteryCharge() {
|
||||
PmicDriver pmic_driver;
|
||||
BatteryDriver battery_driver;
|
||||
ChargerDriver charger_driver;
|
||||
|
||||
if (R_FAILED(battery_driver.InitializeBatteryParameters())) {
|
||||
pmic_driver.ShutdownSystem();
|
||||
}
|
||||
{
|
||||
bool removed;
|
||||
if (R_FAILED(battery_driver.IsBatteryRemoved(&removed)) || removed) {
|
||||
pmic_driver.ShutdownSystem();
|
||||
}
|
||||
}
|
||||
|
||||
const u32 boot_reason = Boot::GetBootReason();
|
||||
InputCurrentLimit input_current_limit;
|
||||
if (R_FAILED(charger_driver.Initialize(boot_reason != 4)) || R_FAILED(charger_driver.GetInputCurrentLimit(&input_current_limit))) {
|
||||
pmic_driver.ShutdownSystem();
|
||||
}
|
||||
|
||||
if (input_current_limit <= InputCurrentLimit_150mA) {
|
||||
charger_driver.SetChargerConfiguration(ChargerConfiguration_ChargeDisable);
|
||||
pmic_driver.ShutdownSystem();
|
||||
}
|
||||
|
||||
const BatteryChargeParameters *params = GetBatteryChargeParameters(Boot::GetBatteryVersion());
|
||||
u32 charge_voltage_limit = params->charge_voltage_limit_default;
|
||||
CheckBatteryResult check_result;
|
||||
if (boot_reason == 4) {
|
||||
if (R_FAILED(charger_driver.GetChargeVoltageLimit(&charge_voltage_limit))) {
|
||||
pmic_driver.ShutdownSystem();
|
||||
}
|
||||
UpdateCharger(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit);
|
||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, true, false, true, false, false);
|
||||
} else {
|
||||
UpdateCharger(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit);
|
||||
if (boot_reason == 1) {
|
||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, true, true, false, true, true);
|
||||
} else {
|
||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, false, true, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
switch (check_result) {
|
||||
case CheckBatteryResult_Success:
|
||||
break;
|
||||
case CheckBatteryResult_Shutdown:
|
||||
pmic_driver.ShutdownSystem();
|
||||
break;
|
||||
case CheckBatteryResult_Reboot:
|
||||
Boot::RebootSystem();
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
48
stratosphere/boot/source/boot_check_clock.cpp
Normal file
48
stratosphere/boot/source/boot_check_clock.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
|
||||
static constexpr u32 ExpectedPlluDivP = (1 << 16);
|
||||
static constexpr u32 ExpectedPlluDivN = (25 << 8);
|
||||
static constexpr u32 ExpectedPlluDivM = (2 << 0);
|
||||
static constexpr u32 ExpectedPlluVal = (ExpectedPlluDivP | ExpectedPlluDivN | ExpectedPlluDivM);
|
||||
static constexpr u32 ExpectedPlluMask = 0x1FFFFF;
|
||||
|
||||
static constexpr u32 ExpectedUtmipDivN = (25 << 16);
|
||||
static constexpr u32 ExpectedUtmipDivM = (1 << 8);
|
||||
static constexpr u32 ExpectedUtmipVal = (ExpectedUtmipDivN | ExpectedUtmipDivM);
|
||||
static constexpr u32 ExpectedUtmipMask = 0xFFFF00;
|
||||
|
||||
static bool IsUsbClockValid() {
|
||||
u64 _vaddr;
|
||||
if (R_FAILED(svcQueryIoMapping(&_vaddr, 0x60006000ul, 0x1000))) {
|
||||
std::abort();
|
||||
}
|
||||
volatile u32 *car_regs = reinterpret_cast<volatile u32 *>(_vaddr);
|
||||
|
||||
const u32 pllu = car_regs[0xC0 >> 2];
|
||||
const u32 utmip = car_regs[0x480 >> 2];
|
||||
return ((pllu & ExpectedPlluMask) == ExpectedPlluVal) && ((utmip & ExpectedUtmipMask) == ExpectedUtmipVal);
|
||||
}
|
||||
|
||||
void Boot::CheckClock() {
|
||||
if (!IsUsbClockValid()) {
|
||||
/* Sleep for 1s, then reboot. */
|
||||
svcSleepThread(1'000'000'000ul);
|
||||
Boot::RebootSystem();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_registers_pmc.hpp"
|
||||
|
||||
static constexpr u32 PmcClkOutCntrl = PmcBase + APBDEV_PMC_CLK_OUT_CNTRL;
|
||||
static constexpr u32 InitialClockOutMask1x = 0x00C4;
|
||||
static constexpr u32 InitialClockOutMask6x = 0xC4C4;
|
||||
|
||||
void Boot::SetInitialClockConfiguration() {
|
||||
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
||||
const u32 mask = GetRuntimeFirmwareVersion() >= FirmwareVersion_600 ? InitialClockOutMask6x : InitialClockOutMask1x;
|
||||
WritePmcRegister(PmcClkOutCntrl, mask, mask);
|
||||
}
|
||||
536
stratosphere/boot/source/boot_display.cpp
Normal file
536
stratosphere/boot/source/boot_display.cpp
Normal file
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_display_config.hpp"
|
||||
#include "i2c_driver/i2c_api.hpp"
|
||||
|
||||
/* Helpful defines. */
|
||||
constexpr size_t DeviceAddressSpaceAlignSize = 0x400000;
|
||||
constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1;
|
||||
constexpr uintptr_t FrameBufferPaddr = DisplayConfigFrameBufferAddress;
|
||||
constexpr size_t FrameBufferWidth = 768;
|
||||
constexpr size_t FrameBufferHeight = 1280;
|
||||
constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||
|
||||
constexpr uintptr_t Disp1Base = 0x54200000ul;
|
||||
constexpr uintptr_t DsiBase = 0x54300000ul;
|
||||
constexpr uintptr_t ClkRstBase = 0x60006000ul;
|
||||
constexpr uintptr_t GpioBase = 0x6000D000ul;
|
||||
constexpr uintptr_t ApbMiscBase = 0x70000000ul;
|
||||
constexpr uintptr_t MipiCalBase = 0x700E3000ul;
|
||||
constexpr size_t Disp1Size = 0x3000;
|
||||
constexpr size_t DsiSize = 0x1000;
|
||||
constexpr size_t ClkRstSize = 0x1000;
|
||||
constexpr size_t GpioSize = 0x1000;
|
||||
constexpr size_t ApbMiscSize = 0x1000;
|
||||
constexpr size_t MipiCalSize = 0x1000;
|
||||
|
||||
/* Types. */
|
||||
|
||||
/* Globals. */
|
||||
static bool g_is_display_intialized = false;
|
||||
static u32 *g_frame_buffer = nullptr;
|
||||
static bool g_is_mariko = false;
|
||||
static u32 g_lcd_vendor = 0;
|
||||
static Handle g_dc_das_hnd = INVALID_HANDLE;
|
||||
static u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize];
|
||||
|
||||
static uintptr_t g_disp1_regs = 0;
|
||||
static uintptr_t g_dsi_regs = 0;
|
||||
static uintptr_t g_clk_rst_regs = 0;
|
||||
static uintptr_t g_gpio_regs = 0;
|
||||
static uintptr_t g_apb_misc_regs = 0;
|
||||
static uintptr_t g_mipi_cal_regs = 0;
|
||||
|
||||
static inline uintptr_t QueryVirtualAddress(uintptr_t phys, size_t size) {
|
||||
uintptr_t aligned_phys = phys & ~0xFFFul;
|
||||
size_t aligned_size = size + (phys - aligned_phys);
|
||||
uintptr_t aligned_virt;
|
||||
if (R_FAILED(svcQueryIoMapping(&aligned_virt, aligned_phys, aligned_size))) {
|
||||
std::abort();
|
||||
}
|
||||
return aligned_virt + (phys - aligned_phys);
|
||||
}
|
||||
|
||||
static inline void WriteRegister(volatile u32 *reg, u32 val) {
|
||||
*reg = val;
|
||||
}
|
||||
|
||||
static inline void WriteRegister(uintptr_t reg, u32 val) {
|
||||
WriteRegister(reinterpret_cast<volatile u32 *>(reg), val);
|
||||
}
|
||||
|
||||
static inline u32 ReadRegister(volatile u32 *reg) {
|
||||
u32 val = *reg;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32 ReadRegister(uintptr_t reg) {
|
||||
return ReadRegister(reinterpret_cast<volatile u32 *>(reg));
|
||||
}
|
||||
|
||||
static inline void SetRegisterBits(volatile u32 *reg, u32 mask) {
|
||||
*reg |= mask;
|
||||
}
|
||||
|
||||
static inline void SetRegisterBits(uintptr_t reg, u32 mask) {
|
||||
SetRegisterBits(reinterpret_cast<volatile u32 *>(reg), mask);
|
||||
}
|
||||
|
||||
static inline void ClearRegisterBits(volatile u32 *reg, u32 mask) {
|
||||
*reg &= mask;
|
||||
}
|
||||
|
||||
static inline void ClearRegisterBits(uintptr_t reg, u32 mask) {
|
||||
ClearRegisterBits(reinterpret_cast<volatile u32 *>(reg), mask);
|
||||
}
|
||||
|
||||
static inline void ReadWriteRegisterBits(volatile u32 *reg, u32 val, u32 mask) {
|
||||
*reg = (*reg & (~mask)) | (val & mask);
|
||||
}
|
||||
|
||||
static inline void ReadWriteRegisterBits(uintptr_t reg, u32 val, u32 mask) {
|
||||
ReadWriteRegisterBits(reinterpret_cast<volatile u32 *>(reg), val, mask);
|
||||
}
|
||||
|
||||
static void InitializeRegisterBaseAddresses() {
|
||||
g_disp1_regs = QueryVirtualAddress(Disp1Base, Disp1Size);
|
||||
g_dsi_regs = QueryVirtualAddress(DsiBase, DsiSize);
|
||||
g_clk_rst_regs = QueryVirtualAddress(ClkRstBase, ClkRstSize);
|
||||
g_gpio_regs = QueryVirtualAddress(GpioBase, GpioSize);
|
||||
g_apb_misc_regs = QueryVirtualAddress(ApbMiscBase, ApbMiscSize);
|
||||
g_mipi_cal_regs = QueryVirtualAddress(MipiCalBase, MipiCalSize);
|
||||
}
|
||||
|
||||
static inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
*(reinterpret_cast<volatile u32 *>(base_address + reg_writes[i].offset)) = reg_writes[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) {
|
||||
if (g_is_mariko) {
|
||||
DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko);
|
||||
} else {
|
||||
DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void DoDsiSleepOrRegisterWrites(const DsiSleepOrRegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Write) {
|
||||
*(reinterpret_cast<volatile u32 *>(g_dsi_regs + sizeof(u32) * reg_writes[i].offset)) = reg_writes[i].value;
|
||||
} else if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Sleep) {
|
||||
svcSleepThread(1'000'000ul * u64(reg_writes[i].offset));
|
||||
} else {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, sizeof(writes) / sizeof(writes[0]))
|
||||
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, sizeof(writes##Erista) / sizeof(writes##Erista[0]), writes##Mariko, sizeof(writes##Mariko) / sizeof(writes##Mariko[0]))
|
||||
#define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, sizeof(writes) / sizeof(writes[0]))
|
||||
|
||||
static void InitializeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
std::memset(g_frame_buffer, 0x00, FrameBufferSize);
|
||||
armDCacheFlush(g_frame_buffer, FrameBufferSize);
|
||||
} else {
|
||||
const uintptr_t frame_buffer_aligned = ((reinterpret_cast<uintptr_t>(g_frame_buffer_storage) + DeviceAddressSpaceAlignMask) & ~uintptr_t(DeviceAddressSpaceAlignMask));
|
||||
g_frame_buffer = reinterpret_cast<u32 *>(frame_buffer_aligned);
|
||||
std::memset(g_frame_buffer, 0x00, FrameBufferSize);
|
||||
armDCacheFlush(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
constexpr u64 DeviceName_DC = 2;
|
||||
|
||||
/* Create Address Space. */
|
||||
if (R_FAILED(svcCreateDeviceAddressSpace(&g_dc_das_hnd, 0, (1ul << 32)))) {
|
||||
std::abort();
|
||||
}
|
||||
/* Attach it to the DC. */
|
||||
if (R_FAILED(svcAttachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
/* Map the framebuffer for the DC as read-only. */
|
||||
if (R_FAILED(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1))) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FinalizeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
const uintptr_t frame_buffer_aligned = reinterpret_cast<uintptr_t>(g_frame_buffer);
|
||||
constexpr u64 DeviceName_DC = 2;
|
||||
|
||||
/* Unmap the framebuffer from the DC. */
|
||||
if (R_FAILED(svcUnmapDeviceAddressSpace(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr))) {
|
||||
std::abort();
|
||||
}
|
||||
/* Detach address space from the DC. */
|
||||
if (R_FAILED(svcDetachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd))) {
|
||||
std::abort();
|
||||
}
|
||||
/* Close the address space. */
|
||||
if (R_FAILED(svcCloseHandle(g_dc_das_hnd))) {
|
||||
std::abort();
|
||||
}
|
||||
g_dc_das_hnd = INVALID_HANDLE;
|
||||
g_frame_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void WaitDsiTrigger() {
|
||||
TimeoutHelper timeout_helper(250'000'000ul);
|
||||
|
||||
while (true) {
|
||||
if (timeout_helper.TimedOut()) {
|
||||
break;
|
||||
}
|
||||
if (ReadRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
svcSleepThread(5'000'000ul);
|
||||
}
|
||||
|
||||
static void WaitDsiHostControl() {
|
||||
TimeoutHelper timeout_helper(150'000'000ul);
|
||||
|
||||
while (true) {
|
||||
if (timeout_helper.TimedOut()) {
|
||||
break;
|
||||
}
|
||||
if ((ReadRegister(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::InitializeDisplay() {
|
||||
/* Setup globals. */
|
||||
InitializeRegisterBaseAddresses();
|
||||
g_is_mariko = Boot::IsMariko();
|
||||
InitializeFrameBuffer();
|
||||
|
||||
/* Turn on DSI/voltage rail. */
|
||||
{
|
||||
I2cSessionImpl i2c_session;
|
||||
I2cDriver::Initialize();
|
||||
I2cDriver::OpenSession(&i2c_session, I2cDevice_Max77620Pmic);
|
||||
|
||||
if (g_is_mariko) {
|
||||
Boot::WriteI2cRegister(i2c_session, 0x18, 0x3A);
|
||||
Boot::WriteI2cRegister(i2c_session, 0x1F, 0x71);
|
||||
}
|
||||
Boot::WriteI2cRegister(i2c_session, 0x23, 0xD0);
|
||||
|
||||
I2cDriver::Finalize();
|
||||
}
|
||||
|
||||
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, 0x1010000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, 0x1010000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, 0x18000000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, 0x18000000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, 0x20000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, 0xA);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, 0x80000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, 0xA);
|
||||
|
||||
/* DPD idle. */
|
||||
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000);
|
||||
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000);
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_EN, ~PINMUX_TRISTATE);
|
||||
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_INT, ~PINMUX_TRISTATE);
|
||||
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, ~PINMUX_TRISTATE);
|
||||
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_EN, ~PINMUX_TRISTATE);
|
||||
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_RST, ~PINMUX_TRISTATE);
|
||||
|
||||
/* Configure LCD power, VDD. */
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
svcSleepThread(10'000'000ul);
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
|
||||
/* Configure display interface and display. */
|
||||
WriteRegister(g_mipi_cal_regs + 0x060, 0);
|
||||
if (g_is_mariko) {
|
||||
WriteRegister(g_mipi_cal_regs + 0x058, 0);
|
||||
WriteRegister(g_apb_misc_regs + 0xAC0, 0);
|
||||
}
|
||||
|
||||
/* Execute configs. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01);
|
||||
/* NOTE: Nintendo bug here. */
|
||||
/* As of 8.0.0, Nintendo writes this list to CAR instead of DSI */
|
||||
/* This results in them zeroing CLK_SOURCE_UARTA... */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07);
|
||||
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Enable backlight reset. */
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
svcSleepThread(60'000'000ul);
|
||||
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
|
||||
WaitDsiHostControl();
|
||||
svcSleepThread(5'000'000ul);
|
||||
|
||||
/* Parse LCD vendor. */
|
||||
{
|
||||
u32 host_response[3];
|
||||
for (size_t i = 0; i < sizeof(host_response) / sizeof(host_response[0]); i++) {
|
||||
host_response[i] = ReadRegister(g_dsi_regs + sizeof(u32) * DSI_RD_DATA);
|
||||
}
|
||||
|
||||
if ((host_response[2] & 0xFF) == 0x10) {
|
||||
g_lcd_vendor = 0;
|
||||
} else {
|
||||
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
|
||||
}
|
||||
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
|
||||
}
|
||||
|
||||
/* LCD vendor specific configuration. */
|
||||
switch (g_lcd_vendor) {
|
||||
case 0xF30: /* TODO: What's this? */
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(180'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0xF20: /* TODO: What's this? */
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(180'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_DSI_SLEEP_OR_REGISTER_WRITES(DisplayConfigJdiSpecificInit01);
|
||||
break;
|
||||
default:
|
||||
if ((g_lcd_vendor | 0x10) == 0x1030) {
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(120'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
}
|
||||
break;
|
||||
}
|
||||
svcSleepThread(20'000'000ul);
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09);
|
||||
|
||||
WriteRegister(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4));
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10);
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Configure MIPI CAL. */
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
if (g_is_mariko) {
|
||||
/* On Mariko the above configurations are executed twice, for some reason. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
}
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Write DISP1, FrameBuffer config. */
|
||||
DO_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02);
|
||||
DO_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer);
|
||||
svcSleepThread(35'000'000ul);
|
||||
g_is_display_intialized = true;
|
||||
}
|
||||
|
||||
void Boot::ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img) {
|
||||
if (!g_is_display_intialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Draw the image to the screen. */
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
{
|
||||
for (size_t cur_y = 0; cur_y < height; cur_y++) {
|
||||
for (size_t cur_x = 0; cur_x < width; cur_x++) {
|
||||
g_frame_buffer[(FrameBufferHeight - (x + cur_x)) * FrameBufferWidth + y + cur_y] = img[cur_y * width + cur_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
armDCacheFlush(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Enable backlight. */
|
||||
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
}
|
||||
|
||||
void Boot::FinalizeDisplay() {
|
||||
if (!g_is_display_intialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable backlight. */
|
||||
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, ~0x1);
|
||||
|
||||
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
|
||||
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_WR_DATA, 0x2805);
|
||||
|
||||
/* Nintendo waits 5 frames before continuing. */
|
||||
{
|
||||
const uintptr_t host1x_vaddr = QueryVirtualAddress(0x500030a4, 4);
|
||||
const u32 start_val = ReadRegister(host1x_vaddr);
|
||||
while (ReadRegister(host1x_vaddr) < start_val + 5) {
|
||||
/* spinlock here. */
|
||||
}
|
||||
}
|
||||
|
||||
WriteRegister(g_disp1_regs + sizeof(u32) * DC_CMD_STATE_ACCESS, (READ_MUX | WRITE_MUX));
|
||||
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
|
||||
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Fini01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Fini02);
|
||||
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Vendor specific shutdown. */
|
||||
switch (g_lcd_vendor) {
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificFini01);
|
||||
break;
|
||||
case 0xF30: /* TODO: What's this? */
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigF30SpecificFini01);
|
||||
svcSleepThread(5'000'000ul);
|
||||
break;
|
||||
case 0x1020: /* TODO: What's this? */
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x115631);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
break;
|
||||
case 0x1030: /* TODO: What's this? */
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x114D31);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(5'000'000ul);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
svcSleepThread(5'000'000ul);
|
||||
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1005);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
svcSleepThread(50'000'000ul);
|
||||
|
||||
/* Disable backlight RST/Voltage. */
|
||||
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, ~0x4);
|
||||
svcSleepThread(10'000'000ul);
|
||||
ClearRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, ~0x2);
|
||||
svcSleepThread(10'000'000ul);
|
||||
ClearRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, ~0x1);
|
||||
svcSleepThread(10'000'000ul);
|
||||
|
||||
/* Cut clock to DSI. */
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, 0x1010000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, 0x1010000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, 0x18000000);
|
||||
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, 0x18000000);
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * 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)));
|
||||
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0);
|
||||
|
||||
/* Final LCD config for PWM */
|
||||
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_CNF_1, ~0x1);
|
||||
SetRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, PINMUX_TRISTATE);
|
||||
ReadWriteRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, 1, 0x3);
|
||||
|
||||
/* Unmap framebuffer from DC virtual address space. */
|
||||
FinalizeFrameBuffer();
|
||||
g_is_display_intialized = false;
|
||||
}
|
||||
676
stratosphere/boot/source/boot_display_config.hpp
Normal file
676
stratosphere/boot/source/boot_display_config.hpp
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
#include "boot_registers_clkrst.hpp"
|
||||
#include "boot_registers_di.hpp"
|
||||
#include "boot_registers_gpio.hpp"
|
||||
#include "boot_registers_pinmux.hpp"
|
||||
#include "boot_registers_pmc.hpp"
|
||||
|
||||
struct RegisterWrite {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum DsiSleepOrRegisterWriteKind : u16 {
|
||||
DsiSleepOrRegisterWriteKind_Write = 0,
|
||||
DsiSleepOrRegisterWriteKind_Sleep = 1,
|
||||
};
|
||||
|
||||
struct DsiSleepOrRegisterWrite {
|
||||
DsiSleepOrRegisterWriteKind kind;
|
||||
u16 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigPlld01Erista[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigPlld01Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDc01[] = {
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_REG_ACT_CONTROL, 0x54},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_DISP_DC_MCCIF_FIFOCTRL, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
|
||||
{sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{sizeof(u32) * DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{sizeof(u32) * DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{sizeof(u32) * DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{sizeof(u32) * 0x4E4, 0},
|
||||
{sizeof(u32) * DC_COM_CRC_CONTROL, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x0},
|
||||
{sizeof(u32) * DSI_INT_ENABLE, 0x0},
|
||||
{sizeof(u32) * DSI_INT_STATUS, 0x0},
|
||||
{sizeof(u32) * DSI_INT_MASK, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init02Erista[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init02Mariko[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init03[] = {
|
||||
{sizeof(u32) * DSI_DCS_CMDS, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init04Erista[] = {
|
||||
/* No register writes. */
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init05[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_CD, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 0x18},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_0_1, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_2_3, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_4_5, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_6_7, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init06[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init07[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsiPhyTimingErista[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsiPhyTimingMariko[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603},
|
||||
};
|
||||
|
||||
static constexpr DsiSleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DsiSleepOrRegisterWriteKind_Sleep, 0xB4, 0},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905},
|
||||
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigPlld02Erista[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigPlld02Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init08[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init09[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30172},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0x40000208},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_LO, 0x40000308},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_LO, 0x40000308},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0x40000308},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_LO, 0x3F3B2B08},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_HI, 0x2CC},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_LO, 0x3F3B2B08},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0x2CC},
|
||||
{sizeof(u32) * DSI_PKT_LEN_0_1, 0xCE0000},
|
||||
{sizeof(u32) * DSI_PKT_LEN_2_3, 0x87001A2},
|
||||
{sizeof(u32) * DSI_PKT_LEN_4_5, 0x190},
|
||||
{sizeof(u32) * DSI_PKT_LEN_6_7, 0x190},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init10[] = {
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 6},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL| DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init11Erista[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * 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)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0}
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal01[] = {
|
||||
{0x60, 0},
|
||||
{0x08, 0xF3F10000},
|
||||
{0x58, 1},
|
||||
{0x60, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal02Erista[] = {
|
||||
{0x60, 0x10010},
|
||||
{0x5C, 0x300},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal02Mariko[] = {
|
||||
{0x60, 0x10010},
|
||||
{0x5C, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal03Erista[] = {
|
||||
{0x38, 0x200200},
|
||||
{0x3C, 0x200200},
|
||||
{0x64, 0x200002},
|
||||
{0x68, 0x200002},
|
||||
{0x14, 0},
|
||||
{0x18, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal03Mariko[] = {
|
||||
{0x38, 0x200006},
|
||||
{0x3C, 0x200006},
|
||||
{0x64, 0x260000},
|
||||
{0x68, 0x260000},
|
||||
{0x14, 0},
|
||||
{0x18, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigMipiCal04[] = {
|
||||
{0x1C, 0},
|
||||
{0x20, 0},
|
||||
{0x24, 0},
|
||||
{0x28, 0},
|
||||
{0x40, 0},
|
||||
{0x44, 0},
|
||||
{0x68, 0},
|
||||
{0x70, 0},
|
||||
{0x74, 0},
|
||||
{0x00, 0x2A000001},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDc02[] = {
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_DV_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{sizeof(u32) * DC_WIN_CSC_YOF, 0xF0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUR, 0},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVR, 0x198},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUG, 0x39B},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVG, 0x32F},
|
||||
{sizeof(u32) * DC_WIN_CSC_KUB, 0x204},
|
||||
{sizeof(u32) * DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{sizeof(u32) * DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{sizeof(u32) * DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{sizeof(u32) * DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{sizeof(u32) * 0x4E4, 0},
|
||||
{sizeof(u32) * DC_COM_CRC_CONTROL, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * 0x716, 0x10000FF},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
/* Set Display timings */
|
||||
{sizeof(u32) * DC_DISP_DISP_TIMING_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1.
|
||||
{sizeof(u32) * DC_DISP_SYNC_WIDTH, 0x10048},
|
||||
{sizeof(u32) * DC_DISP_BACK_PORCH, 0x90048},
|
||||
{sizeof(u32) * DC_DISP_ACTIVE, 0x50002D0},
|
||||
{sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
/* End of Display timings */
|
||||
{sizeof(u32) * DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
|
||||
{sizeof(u32) * DC_COM_PIN_OUTPUT_ENABLE(1), 0},
|
||||
{sizeof(u32) * DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
|
||||
{sizeof(u32) * DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
|
||||
{sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
|
||||
{sizeof(u32) * DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
|
||||
};
|
||||
|
||||
static constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000;
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigFrameBuffer[] = {
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{sizeof(u32) * DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_WIN_POSITION, 0}, //(0,0)
|
||||
{sizeof(u32) * DC_WIN_H_INITIAL_DDA, 0},
|
||||
{sizeof(u32) * DC_WIN_V_INITIAL_DDA, 0},
|
||||
{sizeof(u32) * DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
|
||||
{sizeof(u32) * DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
|
||||
{sizeof(u32) * DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
|
||||
{sizeof(u32) * DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{sizeof(u32) * DC_WIN_BUFFER_CONTROL, 0},
|
||||
{sizeof(u32) * DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{sizeof(u32) * DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address.
|
||||
{sizeof(u32) * DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{sizeof(u32) * DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
|
||||
{sizeof(u32) * DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{sizeof(u32) * DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD.
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Fini01[] = {
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigDsi01Fini02[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigJdiSpecificFini01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x439},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x9483FFB9},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x2139},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x191919D5},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0xB39},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x4F0F41B1},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0xF179A433},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x2D81},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x439},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0xB9},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
static constexpr RegisterWrite DisplayConfigF30SpecificFini01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x439},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x9483FFB9},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x2C39},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x191919D5},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x2C39},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x191919D6},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x19191919},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0xB39},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x711148B1},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x71143209},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x114D31},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x439},
|
||||
{sizeof(u32) * DSI_WR_DATA, 0xB9},
|
||||
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
26
stratosphere/boot/source/boot_fan_enable.cpp
Normal file
26
stratosphere/boot/source/boot_fan_enable.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
|
||||
static constexpr u32 GpioPadName_FanEnable = 0x4B;
|
||||
|
||||
void Boot::SetFanEnabled() {
|
||||
if (Boot::GetHardwareType() == HardwareType_Copper) {
|
||||
Boot::GpioSetDirection(GpioPadName_FanEnable, GpioDirection_Output);
|
||||
Boot::GpioSetValue(GpioPadName_FanEnable, GpioValue_High);
|
||||
}
|
||||
}
|
||||
91
stratosphere/boot/source/boot_functions.hpp
Normal file
91
stratosphere/boot/source/boot_functions.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
#include "i2c_driver/i2c_types.hpp"
|
||||
|
||||
class Boot {
|
||||
public:
|
||||
static constexpr u32 GpioPhysicalBase = 0x6000D000;
|
||||
static constexpr u32 ApbMiscPhysicalBase = 0x70000000;
|
||||
public:
|
||||
/* Functions for actually booting. */
|
||||
static void ChangeGpioVoltageTo1_8v();
|
||||
static void SetInitialGpioConfiguration();
|
||||
static void CheckClock();
|
||||
static void DetectBootReason();
|
||||
static void ShowSplashScreen();
|
||||
static void CheckBatteryCharge();
|
||||
static void SetInitialClockConfiguration();
|
||||
static void ConfigurePinmux();
|
||||
static void SetInitialWakePinConfiguration();
|
||||
static void SetFanEnabled();
|
||||
static void CheckAndRepairBootImages();
|
||||
|
||||
/* Power utilities. */
|
||||
static void RebootSystem();
|
||||
static void ShutdownSystem();
|
||||
|
||||
/* Register Utilities. */
|
||||
static u32 ReadPmcRegister(u32 phys_addr);
|
||||
static void WritePmcRegister(u32 phys_addr, u32 value, u32 mask = UINT32_MAX);
|
||||
|
||||
/* GPIO Utilities. */
|
||||
static u32 GpioConfigure(u32 gpio_pad_name);
|
||||
static u32 GpioSetDirection(u32 gpio_pad_name, GpioDirection dir);
|
||||
static u32 GpioSetValue(u32 gpio_pad_name, GpioValue val);
|
||||
|
||||
/* Pinmux Utilities. */
|
||||
static u32 PinmuxUpdatePark(u32 pinmux_name);
|
||||
static u32 PinmuxUpdatePad(u32 pinmux_name, u32 config_val, u32 config_mask);
|
||||
static u32 PinmuxUpdateDrivePad(u32 pinmux_drivepad_name, u32 config_val, u32 config_mask);
|
||||
static void ConfigurePinmuxInitialPads();
|
||||
static void ConfigurePinmuxInitialDrivePads();
|
||||
|
||||
/* SPL Utilities. */
|
||||
static HardwareType GetHardwareType();
|
||||
static u32 GetBootReason();
|
||||
static bool IsRecoveryBoot();
|
||||
static bool IsMariko();
|
||||
|
||||
/* I2C Utilities. */
|
||||
static Result ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
||||
static Result WriteI2cRegister(I2cSessionImpl &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
|
||||
static Result WriteI2cRegister(I2cSessionImpl &session, const u8 address, const u8 value);
|
||||
|
||||
/* Splash Screen/Display utilities. */
|
||||
static void InitializeDisplay();
|
||||
static void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img);
|
||||
static void FinalizeDisplay();
|
||||
|
||||
/* Battery Display utilities. */
|
||||
static void ShowLowBatteryIcon();
|
||||
static void StartShowChargingIcon(size_t battery_percentage, bool wait);
|
||||
static void EndShowChargingIcon();
|
||||
|
||||
/* Calibration utilities. */
|
||||
static u16 GetCrc16(const void *data, size_t size);
|
||||
static u32 GetBatteryVersion();
|
||||
static u32 GetBatteryVendor();
|
||||
|
||||
/* Wake pin utiliies. */
|
||||
static void SetWakeEventLevel(u32 index, u32 level);
|
||||
static void SetWakeEventEnabled(u32 index, bool enabled);
|
||||
};
|
||||
80
stratosphere/boot/source/boot_gpio_initial_configuration.cpp
Normal file
80
stratosphere/boot/source/boot_gpio_initial_configuration.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_gpio_initial_configuration_icosa.hpp"
|
||||
#include "boot_gpio_initial_configuration_copper.hpp"
|
||||
#include "boot_gpio_initial_configuration_hoag.hpp"
|
||||
#include "boot_gpio_initial_configuration_iowa.hpp"
|
||||
|
||||
void Boot::SetInitialGpioConfiguration() {
|
||||
const GpioInitialConfig *configs = nullptr;
|
||||
size_t num_configs = 0;
|
||||
const HardwareType hw_type = Boot::GetHardwareType();
|
||||
const FirmwareVersion fw_ver = GetRuntimeFirmwareVersion();
|
||||
|
||||
/* Choose GPIO map. */
|
||||
if (fw_ver >= FirmwareVersion_200) {
|
||||
switch (hw_type) {
|
||||
case HardwareType_Icosa:
|
||||
{
|
||||
if (fw_ver >= FirmwareVersion_400) {
|
||||
configs = GpioInitialConfigsIcosa4x;
|
||||
num_configs = GpioNumInitialConfigsIcosa4x;
|
||||
} else {
|
||||
configs = GpioInitialConfigsIcosa;
|
||||
num_configs = GpioNumInitialConfigsIcosa;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HardwareType_Copper:
|
||||
configs = GpioInitialConfigsCopper;
|
||||
num_configs = GpioNumInitialConfigsCopper;
|
||||
break;
|
||||
case HardwareType_Hoag:
|
||||
configs = GpioInitialConfigsHoag;
|
||||
num_configs = GpioNumInitialConfigsHoag;
|
||||
break;
|
||||
case HardwareType_Iowa:
|
||||
configs = GpioInitialConfigsIowa;
|
||||
num_configs = GpioNumInitialConfigsIowa;
|
||||
break;
|
||||
default:
|
||||
/* Unknown hardware type, we can't proceed. */
|
||||
std::abort();
|
||||
}
|
||||
} else {
|
||||
/* Until 2.0.0, the GPIO map for Icosa was used for all hardware types. */
|
||||
configs = GpioInitialConfigsIcosa;
|
||||
num_configs = GpioNumInitialConfigsIcosa;
|
||||
}
|
||||
|
||||
/* Ensure we found an appropriate config. */
|
||||
if (configs == nullptr) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_configs; i++) {
|
||||
/* Configure the GPIO. */
|
||||
Boot::GpioConfigure(configs[i].pad_name);
|
||||
|
||||
/* Set the GPIO's direction. */
|
||||
Boot::GpioSetDirection(configs[i].pad_name, configs[i].direction);
|
||||
|
||||
/* Set the GPIO's value. */
|
||||
Boot::GpioSetValue(configs[i].pad_name, configs[i].value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr GpioInitialConfig GpioInitialConfigsCopper[] = {
|
||||
{0x40, GpioDirection_Output, GpioValue_Low},
|
||||
{0x05, GpioDirection_Output, GpioValue_Low},
|
||||
{0x41, GpioDirection_Input, GpioValue_High},
|
||||
{0x42, GpioDirection_Input, GpioValue_Low},
|
||||
{0x43, GpioDirection_Output, GpioValue_Low},
|
||||
{0x02, GpioDirection_Output, GpioValue_Low},
|
||||
{0x07, GpioDirection_Output, GpioValue_Low},
|
||||
{0x44, GpioDirection_Input, GpioValue_High},
|
||||
{0x45, GpioDirection_Input, GpioValue_High},
|
||||
{0x0F, GpioDirection_Input, GpioValue_High},
|
||||
{0x46, GpioDirection_Output, GpioValue_Low},
|
||||
{0x47, GpioDirection_Output, GpioValue_Low},
|
||||
{0x10, GpioDirection_Input, GpioValue_Low},
|
||||
{0x11, GpioDirection_Input, GpioValue_Low},
|
||||
{0x12, GpioDirection_Input, GpioValue_Low},
|
||||
{0x13, GpioDirection_Input, GpioValue_Low},
|
||||
{0x14, GpioDirection_Input, GpioValue_High},
|
||||
{0x18, GpioDirection_Input, GpioValue_Low},
|
||||
{0x19, GpioDirection_Input, GpioValue_High},
|
||||
{0x1A, GpioDirection_Input, GpioValue_High},
|
||||
{0x1C, GpioDirection_Input, GpioValue_High},
|
||||
{0x4D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x20, GpioDirection_Output, GpioValue_Low},
|
||||
{0x38, GpioDirection_Input, GpioValue_High},
|
||||
{0x23, GpioDirection_Input, GpioValue_High},
|
||||
{0x25, GpioDirection_Input, GpioValue_Low},
|
||||
{0x26, GpioDirection_Input, GpioValue_Low},
|
||||
{0x27, GpioDirection_Input, GpioValue_Low},
|
||||
{0x28, GpioDirection_Input, GpioValue_High},
|
||||
{0x29, GpioDirection_Input, GpioValue_High},
|
||||
{0x2A, GpioDirection_Input, GpioValue_High},
|
||||
{0x48, GpioDirection_Output, GpioValue_Low},
|
||||
{0x49, GpioDirection_Output, GpioValue_Low},
|
||||
{0x4A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x37, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x03, GpioDirection_Output, GpioValue_Low},
|
||||
{0x30, GpioDirection_Input, GpioValue_Low},
|
||||
{0x31, GpioDirection_Output, GpioValue_Low},
|
||||
{0x4B, GpioDirection_Output, GpioValue_Low},
|
||||
{0x4C, GpioDirection_Input, GpioValue_High},
|
||||
{0x4E, GpioDirection_Input, GpioValue_Low},
|
||||
};
|
||||
|
||||
static constexpr u32 GpioNumInitialConfigsCopper = (sizeof(GpioInitialConfigsCopper) / sizeof(GpioInitialConfigsCopper[0]));
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr GpioInitialConfig GpioInitialConfigsHoag[] = {
|
||||
{0x04, GpioDirection_Input, GpioValue_High},
|
||||
{0x05, GpioDirection_Output, GpioValue_Low},
|
||||
{0x06, GpioDirection_Input, GpioValue_Low},
|
||||
{0x02, GpioDirection_Output, GpioValue_Low},
|
||||
{0x3C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0F, GpioDirection_Input, GpioValue_High},
|
||||
{0x08, GpioDirection_Input, GpioValue_Low},
|
||||
{0x09, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0E, GpioDirection_Input, GpioValue_Low},
|
||||
{0x10, GpioDirection_Input, GpioValue_Low},
|
||||
{0x11, GpioDirection_Input, GpioValue_Low},
|
||||
{0x12, GpioDirection_Input, GpioValue_Low},
|
||||
{0x13, GpioDirection_Input, GpioValue_Low},
|
||||
{0x14, GpioDirection_Input, GpioValue_High},
|
||||
{0x16, GpioDirection_Input, GpioValue_Low},
|
||||
{0x15, GpioDirection_Input, GpioValue_Low},
|
||||
{0x17, GpioDirection_Input, GpioValue_High},
|
||||
{0x18, GpioDirection_Input, GpioValue_Low},
|
||||
{0x19, GpioDirection_Input, GpioValue_High},
|
||||
{0x1A, GpioDirection_Input, GpioValue_High},
|
||||
{0x1B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x1E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x20, GpioDirection_Output, GpioValue_Low},
|
||||
{0x21, GpioDirection_Input, GpioValue_Low},
|
||||
{0x38, GpioDirection_Input, GpioValue_High},
|
||||
{0x22, GpioDirection_Input, GpioValue_Low},
|
||||
{0x23, GpioDirection_Input, GpioValue_High},
|
||||
{0x01, GpioDirection_Output, GpioValue_Low},
|
||||
{0x39, GpioDirection_Output, GpioValue_Low},
|
||||
{0x24, GpioDirection_Output, GpioValue_Low},
|
||||
{0x34, GpioDirection_Input, GpioValue_Low},
|
||||
{0x25, GpioDirection_Input, GpioValue_Low},
|
||||
{0x26, GpioDirection_Input, GpioValue_Low},
|
||||
{0x27, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2B, GpioDirection_Output, GpioValue_Low},
|
||||
{0x28, GpioDirection_Input, GpioValue_High},
|
||||
{0x1F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x29, GpioDirection_Input, GpioValue_High},
|
||||
{0x3A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x37, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x03, GpioDirection_Output, GpioValue_Low},
|
||||
{0x30, GpioDirection_Input, GpioValue_Low},
|
||||
{0x3B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x31, GpioDirection_Output, GpioValue_Low},
|
||||
{0x32, GpioDirection_Output, GpioValue_Low},
|
||||
{0x33, GpioDirection_Output, GpioValue_Low},
|
||||
{0x35, GpioDirection_Input, GpioValue_High},
|
||||
{0x2C, GpioDirection_Output, GpioValue_Low},
|
||||
{0x36, GpioDirection_Output, GpioValue_Low},
|
||||
|
||||
};
|
||||
|
||||
static constexpr u32 GpioNumInitialConfigsHoag = (sizeof(GpioInitialConfigsHoag) / sizeof(GpioInitialConfigsHoag[0]));
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr GpioInitialConfig GpioInitialConfigsIcosa[] = {
|
||||
{0x04, GpioDirection_Input, GpioValue_High},
|
||||
{0x05, GpioDirection_Output, GpioValue_Low},
|
||||
{0x06, GpioDirection_Input, GpioValue_Low},
|
||||
{0x02, GpioDirection_Output, GpioValue_Low},
|
||||
{0x07, GpioDirection_Output, GpioValue_Low},
|
||||
{0x3C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0F, GpioDirection_Input, GpioValue_High},
|
||||
{0x08, GpioDirection_Input, GpioValue_Low},
|
||||
{0x09, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0B, GpioDirection_Input, GpioValue_High},
|
||||
{0x0D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0E, GpioDirection_Input, GpioValue_Low},
|
||||
{0x10, GpioDirection_Input, GpioValue_Low},
|
||||
{0x11, GpioDirection_Input, GpioValue_Low},
|
||||
{0x12, GpioDirection_Input, GpioValue_Low},
|
||||
{0x13, GpioDirection_Input, GpioValue_Low},
|
||||
{0x14, GpioDirection_Input, GpioValue_High},
|
||||
{0x16, GpioDirection_Input, GpioValue_Low},
|
||||
{0x15, GpioDirection_Input, GpioValue_Low},
|
||||
{0x17, GpioDirection_Input, GpioValue_High},
|
||||
{0x18, GpioDirection_Input, GpioValue_Low},
|
||||
{0x19, GpioDirection_Input, GpioValue_High},
|
||||
{0x1A, GpioDirection_Input, GpioValue_High},
|
||||
{0x1B, GpioDirection_Input, GpioValue_High},
|
||||
{0x1C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x1E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x20, GpioDirection_Output, GpioValue_Low},
|
||||
{0x21, GpioDirection_Input, GpioValue_High},
|
||||
{0x38, GpioDirection_Input, GpioValue_High},
|
||||
{0x22, GpioDirection_Input, GpioValue_Low},
|
||||
{0x23, GpioDirection_Input, GpioValue_High},
|
||||
{0x01, GpioDirection_Output, GpioValue_Low},
|
||||
{0x39, GpioDirection_Output, GpioValue_Low},
|
||||
{0x24, GpioDirection_Output, GpioValue_Low},
|
||||
{0x34, GpioDirection_Input, GpioValue_Low},
|
||||
{0x25, GpioDirection_Input, GpioValue_Low},
|
||||
{0x26, GpioDirection_Input, GpioValue_Low},
|
||||
{0x27, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2B, GpioDirection_Output, GpioValue_Low},
|
||||
{0x28, GpioDirection_Input, GpioValue_High},
|
||||
{0x1F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x29, GpioDirection_Input, GpioValue_High},
|
||||
{0x2A, GpioDirection_Input, GpioValue_High},
|
||||
{0x3A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x37, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x03, GpioDirection_Output, GpioValue_Low},
|
||||
{0x30, GpioDirection_Input, GpioValue_Low},
|
||||
{0x3B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x31, GpioDirection_Output, GpioValue_Low},
|
||||
{0x32, GpioDirection_Output, GpioValue_Low},
|
||||
{0x33, GpioDirection_Output, GpioValue_Low},
|
||||
{0x35, GpioDirection_Input, GpioValue_High},
|
||||
{0x2C, GpioDirection_Output, GpioValue_Low},
|
||||
{0x36, GpioDirection_Output, GpioValue_Low},
|
||||
};
|
||||
|
||||
static constexpr u32 GpioNumInitialConfigsIcosa = (sizeof(GpioInitialConfigsIcosa) / sizeof(GpioInitialConfigsIcosa[0]));
|
||||
|
||||
static constexpr GpioInitialConfig GpioInitialConfigsIcosa4x[] = {
|
||||
{0x04, GpioDirection_Input, GpioValue_High},
|
||||
{0x05, GpioDirection_Output, GpioValue_Low},
|
||||
{0x06, GpioDirection_Input, GpioValue_Low},
|
||||
{0x02, GpioDirection_Output, GpioValue_Low},
|
||||
{0x07, GpioDirection_Output, GpioValue_Low},
|
||||
{0x3C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0F, GpioDirection_Input, GpioValue_High},
|
||||
{0x08, GpioDirection_Input, GpioValue_Low},
|
||||
{0x09, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0B, GpioDirection_Input, GpioValue_High},
|
||||
{0x0D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0E, GpioDirection_Input, GpioValue_Low},
|
||||
{0x10, GpioDirection_Input, GpioValue_Low},
|
||||
{0x11, GpioDirection_Input, GpioValue_Low},
|
||||
{0x12, GpioDirection_Input, GpioValue_Low},
|
||||
{0x13, GpioDirection_Input, GpioValue_Low},
|
||||
{0x14, GpioDirection_Input, GpioValue_High},
|
||||
{0x16, GpioDirection_Input, GpioValue_Low},
|
||||
{0x15, GpioDirection_Input, GpioValue_Low},
|
||||
{0x17, GpioDirection_Input, GpioValue_High},
|
||||
{0x18, GpioDirection_Input, GpioValue_High},
|
||||
{0x19, GpioDirection_Input, GpioValue_High},
|
||||
{0x1A, GpioDirection_Input, GpioValue_High},
|
||||
{0x1B, GpioDirection_Input, GpioValue_High},
|
||||
{0x1C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x1E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x20, GpioDirection_Output, GpioValue_Low},
|
||||
{0x21, GpioDirection_Input, GpioValue_High},
|
||||
{0x38, GpioDirection_Input, GpioValue_High},
|
||||
{0x22, GpioDirection_Input, GpioValue_Low},
|
||||
{0x23, GpioDirection_Input, GpioValue_High},
|
||||
{0x01, GpioDirection_Output, GpioValue_Low},
|
||||
{0x39, GpioDirection_Output, GpioValue_Low},
|
||||
{0x24, GpioDirection_Output, GpioValue_Low},
|
||||
{0x34, GpioDirection_Input, GpioValue_Low},
|
||||
{0x25, GpioDirection_Input, GpioValue_Low},
|
||||
{0x26, GpioDirection_Input, GpioValue_Low},
|
||||
{0x27, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2B, GpioDirection_Output, GpioValue_Low},
|
||||
{0x28, GpioDirection_Input, GpioValue_High},
|
||||
{0x1F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x29, GpioDirection_Input, GpioValue_High},
|
||||
{0x2A, GpioDirection_Input, GpioValue_High},
|
||||
{0x3A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x37, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x03, GpioDirection_Output, GpioValue_Low},
|
||||
{0x30, GpioDirection_Input, GpioValue_Low},
|
||||
{0x3B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x31, GpioDirection_Output, GpioValue_Low},
|
||||
{0x32, GpioDirection_Output, GpioValue_Low},
|
||||
{0x33, GpioDirection_Output, GpioValue_Low},
|
||||
{0x35, GpioDirection_Input, GpioValue_High},
|
||||
{0x2C, GpioDirection_Output, GpioValue_Low},
|
||||
{0x36, GpioDirection_Output, GpioValue_Low},
|
||||
};
|
||||
|
||||
static constexpr u32 GpioNumInitialConfigsIcosa4x = (sizeof(GpioInitialConfigsIcosa4x) / sizeof(GpioInitialConfigsIcosa4x[0]));
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr GpioInitialConfig GpioInitialConfigsIowa[] = {
|
||||
{0x04, GpioDirection_Input, GpioValue_High},
|
||||
{0x05, GpioDirection_Output, GpioValue_Low},
|
||||
{0x06, GpioDirection_Input, GpioValue_Low},
|
||||
{0x02, GpioDirection_Output, GpioValue_Low},
|
||||
{0x3C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0F, GpioDirection_Input, GpioValue_High},
|
||||
{0x08, GpioDirection_Input, GpioValue_Low},
|
||||
{0x09, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x0D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0E, GpioDirection_Input, GpioValue_Low},
|
||||
{0x10, GpioDirection_Input, GpioValue_Low},
|
||||
{0x11, GpioDirection_Input, GpioValue_Low},
|
||||
{0x12, GpioDirection_Input, GpioValue_Low},
|
||||
{0x13, GpioDirection_Input, GpioValue_Low},
|
||||
{0x14, GpioDirection_Input, GpioValue_High},
|
||||
{0x16, GpioDirection_Input, GpioValue_Low},
|
||||
{0x15, GpioDirection_Input, GpioValue_Low},
|
||||
{0x17, GpioDirection_Input, GpioValue_High},
|
||||
{0x18, GpioDirection_Input, GpioValue_Low},
|
||||
{0x19, GpioDirection_Input, GpioValue_High},
|
||||
{0x1A, GpioDirection_Input, GpioValue_High},
|
||||
{0x1B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x1D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x1E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x20, GpioDirection_Output, GpioValue_Low},
|
||||
{0x21, GpioDirection_Input, GpioValue_Low},
|
||||
{0x38, GpioDirection_Input, GpioValue_High},
|
||||
{0x22, GpioDirection_Input, GpioValue_Low},
|
||||
{0x23, GpioDirection_Input, GpioValue_High},
|
||||
{0x01, GpioDirection_Output, GpioValue_Low},
|
||||
{0x39, GpioDirection_Output, GpioValue_Low},
|
||||
{0x24, GpioDirection_Output, GpioValue_Low},
|
||||
{0x34, GpioDirection_Input, GpioValue_Low},
|
||||
{0x25, GpioDirection_Input, GpioValue_Low},
|
||||
{0x26, GpioDirection_Input, GpioValue_Low},
|
||||
{0x27, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2B, GpioDirection_Output, GpioValue_Low},
|
||||
{0x28, GpioDirection_Input, GpioValue_High},
|
||||
{0x1F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x29, GpioDirection_Input, GpioValue_High},
|
||||
{0x3A, GpioDirection_Output, GpioValue_Low},
|
||||
{0x0C, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2D, GpioDirection_Output, GpioValue_Low},
|
||||
{0x2E, GpioDirection_Output, GpioValue_Low},
|
||||
{0x37, GpioDirection_Input, GpioValue_Low},
|
||||
{0x2F, GpioDirection_Output, GpioValue_Low},
|
||||
{0x03, GpioDirection_Output, GpioValue_Low},
|
||||
{0x30, GpioDirection_Input, GpioValue_Low},
|
||||
{0x3B, GpioDirection_Input, GpioValue_Low},
|
||||
{0x31, GpioDirection_Output, GpioValue_Low},
|
||||
{0x32, GpioDirection_Output, GpioValue_Low},
|
||||
{0x33, GpioDirection_Output, GpioValue_Low},
|
||||
{0x35, GpioDirection_Input, GpioValue_High},
|
||||
{0x2C, GpioDirection_Output, GpioValue_Low},
|
||||
{0x36, GpioDirection_Output, GpioValue_Low},
|
||||
|
||||
};
|
||||
|
||||
static constexpr u32 GpioNumInitialConfigsIowa = (sizeof(GpioInitialConfigsIowa) / sizeof(GpioInitialConfigsIowa[0]));
|
||||
111
stratosphere/boot/source/boot_gpio_map.hpp
Normal file
111
stratosphere/boot/source/boot_gpio_map.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
static constexpr u32 GpioInvalid = UINT32_MAX;
|
||||
|
||||
static constexpr u32 GpioMap[] = {
|
||||
GpioInvalid, /* Invalid */
|
||||
0x000000CC, /* Port Z, Pin 4 */
|
||||
0x00000024, /* Port E, Pin 4 */
|
||||
0x0000003C, /* Port H, Pin 4 */
|
||||
0x000000DA, /* Port BB, Pin 2 */
|
||||
0x000000DB, /* Port BB, Pin 3 */
|
||||
0x000000DC, /* Port BB, Pin 4 */
|
||||
0x00000025, /* Port E, Pin 5 */
|
||||
0x00000090, /* Port S, Pin 0 */
|
||||
0x00000091, /* Port S, Pin 1 */
|
||||
0x00000096, /* Port S, Pin 6 */
|
||||
0x00000097, /* Port S, Pin 7 */
|
||||
0x00000026, /* Port E, Pin 6 */
|
||||
0x00000005, /* Port A, Pin 5 */
|
||||
0x00000078, /* Port P, Pin 0 */
|
||||
0x00000093, /* Port S, Pin 3 */
|
||||
0x0000007D, /* Port P, Pin 5 */
|
||||
0x0000007C, /* Port P, Pin 4 */
|
||||
0x0000007B, /* Port P, Pin 3 */
|
||||
0x0000007A, /* Port P, Pin 2 */
|
||||
0x000000BC, /* Port X, Pin 4 */
|
||||
0x000000AE, /* Port V, Pin 6 */
|
||||
0x000000BA, /* Port X, Pin 2 */
|
||||
0x000000B9, /* Port X, Pin 1 */
|
||||
0x000000BD, /* Port X, Pin 5 */
|
||||
0x000000BE, /* Port X, Pin 6 */
|
||||
0x000000BF, /* Port X, Pin 7 */
|
||||
0x000000C0, /* Port Y, Pin 0 */
|
||||
0x000000C1, /* Port Y, Pin 1 */
|
||||
0x000000A9, /* Port V, Pin 1 */
|
||||
0x000000AA, /* Port V, Pin 2 */
|
||||
0x00000055, /* Port K, Pin 5 */
|
||||
0x000000AD, /* Port V, Pin 5 */
|
||||
0x000000C8, /* Port Z, Pin 0 */
|
||||
0x000000CA, /* Port Z, Pin 2 */
|
||||
0x000000CB, /* Port Z, Pin 3 */
|
||||
0x0000004F, /* Port J, Pin 7 */
|
||||
0x00000050, /* Port K, Pin 0 */
|
||||
0x00000051, /* Port K, Pin 1 */
|
||||
0x00000052, /* Port K, Pin 2 */
|
||||
0x00000054, /* Port K, Pin 4 */
|
||||
0x00000056, /* Port K, Pin 6 */
|
||||
0x00000057, /* Port K, Pin 7 */
|
||||
0x00000053, /* Port K, Pin 3 */
|
||||
0x000000E3, /* Port CC, Pin 3 */
|
||||
0x00000038, /* Port H, Pin 0 */
|
||||
0x00000039, /* Port H, Pin 1 */
|
||||
0x0000003B, /* Port H, Pin 3 */
|
||||
0x0000003D, /* Port H, Pin 5 */
|
||||
0x0000003F, /* Port H, Pin 7 */
|
||||
0x00000040, /* Port I, Pin 0 */
|
||||
0x00000041, /* Port I, Pin 1 */
|
||||
0x0000003E, /* Port H, Pin 6 */
|
||||
0x000000E2, /* Port CC, Pin 2 */
|
||||
0x000000E4, /* Port CC, Pin 4 */
|
||||
0x0000003A, /* Port H, Pin 2 */
|
||||
0x000000C9, /* Port Z, Pin 1 */
|
||||
0x0000004D, /* Port J, Pin 5 */
|
||||
0x00000058, /* Port L, Pin 0 */
|
||||
0x0000003E, /* Port H, Pin 6 */
|
||||
0x00000026, /* Port E, Pin 6 */
|
||||
|
||||
/* Copper only */
|
||||
GpioInvalid, /* Invalid */
|
||||
0x00000033, /* Port G, Pin 3 */
|
||||
0x0000001C, /* Port D, Pin 4 */
|
||||
0x000000D9, /* Port BB, Pin 1 */
|
||||
0x0000000C, /* Port B, Pin 4 */
|
||||
0x0000000D, /* Port B, Pin 5 */
|
||||
0x00000021, /* Port E, Pin 1 */
|
||||
0x00000027, /* Port E, Pin 7 */
|
||||
0x00000092, /* Port S, Pin 2 */
|
||||
0x00000095, /* Port S, Pin 5 */
|
||||
0x00000098, /* Port T, Pin 0 */
|
||||
0x00000010, /* Port C, Pin 0 */
|
||||
0x00000011, /* Port C, Pin 1 */
|
||||
0x00000012, /* Port C, Pin 2 */
|
||||
0x00000042, /* Port I, Pin 2 */
|
||||
0x000000E6, /* Port CC, Pin 6 */
|
||||
|
||||
/* 2.0.0+ Copper only */
|
||||
0x000000AC, /* Port V, Pin 4 */
|
||||
0x000000E1, /* Port CC, Pin 1 */
|
||||
|
||||
/* 5.0.0+ Copper only (unused) */
|
||||
0x00000056, /* Port K, Pin 6 */
|
||||
};
|
||||
|
||||
static constexpr u32 GpioPadNameMax = (sizeof(GpioMap) / sizeof(GpioMap[0]));
|
||||
119
stratosphere/boot/source/boot_gpio_utils.cpp
Normal file
119
stratosphere/boot/source/boot_gpio_utils.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_gpio_map.hpp"
|
||||
|
||||
static bool g_initialized_gpio_vaddr = false;
|
||||
static uintptr_t g_gpio_vaddr = 0;
|
||||
|
||||
static inline u32 GetGpioPadDescriptor(u32 gpio_pad_name) {
|
||||
if (gpio_pad_name >= GpioPadNameMax) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return GpioMap[gpio_pad_name];
|
||||
}
|
||||
|
||||
static uintptr_t GetGpioBaseAddress() {
|
||||
if (!g_initialized_gpio_vaddr) {
|
||||
u64 vaddr;
|
||||
if (R_FAILED(svcQueryIoMapping(&vaddr, Boot::GpioPhysicalBase, 0x1000))) {
|
||||
std::abort();
|
||||
}
|
||||
g_gpio_vaddr = vaddr;
|
||||
g_initialized_gpio_vaddr = true;
|
||||
}
|
||||
return g_gpio_vaddr;
|
||||
}
|
||||
|
||||
u32 Boot::GpioConfigure(u32 gpio_pad_name) {
|
||||
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
|
||||
|
||||
/* Fetch this GPIO's pad descriptor */
|
||||
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
|
||||
|
||||
/* Discard invalid GPIOs */
|
||||
if (gpio_pad_desc == GpioInvalid) {
|
||||
return GpioInvalid;
|
||||
}
|
||||
|
||||
/* Convert the GPIO pad descriptor into its register offset */
|
||||
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
|
||||
|
||||
/* Extract the bit and lock values from the GPIO pad descriptor */
|
||||
u32 gpio_cnf_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (0x01 << (gpio_pad_desc & 0x07)));
|
||||
|
||||
/* Write to the appropriate GPIO_CNF_x register (upper offset) */
|
||||
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x80)) = gpio_cnf_val;
|
||||
|
||||
/* Do a dummy read from GPIO_CNF_x register (lower offset) */
|
||||
gpio_cnf_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset));
|
||||
|
||||
return gpio_cnf_val;
|
||||
}
|
||||
|
||||
u32 Boot::GpioSetDirection(u32 gpio_pad_name, GpioDirection dir) {
|
||||
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
|
||||
|
||||
/* Fetch this GPIO's pad descriptor */
|
||||
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
|
||||
|
||||
/* Discard invalid GPIOs */
|
||||
if (gpio_pad_desc == GpioInvalid) {
|
||||
return GpioInvalid;
|
||||
}
|
||||
|
||||
/* Convert the GPIO pad descriptor into its register offset */
|
||||
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
|
||||
|
||||
/* Set the direction bit and lock values */
|
||||
u32 gpio_oe_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(dir) << (gpio_pad_desc & 0x07)));
|
||||
|
||||
/* Write to the appropriate GPIO_OE_x register (upper offset) */
|
||||
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x90)) = gpio_oe_val;
|
||||
|
||||
/* Do a dummy read from GPIO_OE_x register (lower offset) */
|
||||
gpio_oe_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x10));
|
||||
|
||||
return gpio_oe_val;
|
||||
}
|
||||
|
||||
u32 Boot::GpioSetValue(u32 gpio_pad_name, GpioValue val) {
|
||||
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
|
||||
|
||||
/* Fetch this GPIO's pad descriptor */
|
||||
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
|
||||
|
||||
/* Discard invalid GPIOs */
|
||||
if (gpio_pad_desc == GpioInvalid) {
|
||||
return GpioInvalid;
|
||||
}
|
||||
|
||||
/* Convert the GPIO pad descriptor into its register offset */
|
||||
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
|
||||
|
||||
/* Set the output bit and lock values */
|
||||
u32 gpio_out_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(val) << (gpio_pad_desc & 0x07)));
|
||||
|
||||
/* Write to the appropriate GPIO_OUT_x register (upper offset) */
|
||||
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0xA0)) = gpio_out_val;
|
||||
|
||||
/* Do a dummy read from GPIO_OUT_x register (lower offset) */
|
||||
gpio_out_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x20));
|
||||
|
||||
return gpio_out_val;
|
||||
}
|
||||
75
stratosphere/boot/source/boot_i2c_utils.cpp
Normal file
75
stratosphere/boot/source/boot_i2c_utils.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "i2c_driver/i2c_api.hpp"
|
||||
|
||||
template<typename F>
|
||||
static Result RetryUntilSuccess(F f) {
|
||||
constexpr u64 timeout = 10'000'000'000ul;
|
||||
constexpr u64 retry_interval = 20'000'000ul;
|
||||
|
||||
u64 cur_time = 0;
|
||||
while (true) {
|
||||
Result rc = f();
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
return rc;
|
||||
} else {
|
||||
cur_time += retry_interval;
|
||||
if (cur_time >= timeout) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
svcSleepThread(retry_interval);
|
||||
}
|
||||
}
|
||||
|
||||
Result Boot::ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) {
|
||||
Result rc;
|
||||
if (dst == nullptr || dst_size == 0 || cmd == nullptr || cmd_size == 0) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
u8 cmd_list[I2cCommandListFormatter::MaxCommandListSize];
|
||||
|
||||
I2cCommandListFormatter formatter(cmd_list, sizeof(cmd_list));
|
||||
if (R_FAILED((rc = formatter.EnqueueSendCommand(I2cTransactionOption_Start, cmd, cmd_size)))) {
|
||||
std::abort();
|
||||
}
|
||||
if (R_FAILED((rc = formatter.EnqueueReceiveCommand(static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop), dst_size)))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return RetryUntilSuccess([&]() { return I2cDriver::ExecuteCommandList(session, dst, dst_size, cmd_list, formatter.GetCurrentSize()); });
|
||||
}
|
||||
|
||||
Result Boot::WriteI2cRegister(I2cSessionImpl &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) {
|
||||
if (src == nullptr || src_size == 0 || cmd == nullptr || cmd_size == 0) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
u8 cmd_list[0x20];
|
||||
|
||||
/* N doesn't use a CommandListFormatter here... */
|
||||
std::memcpy(&cmd_list[0], cmd, cmd_size);
|
||||
std::memcpy(&cmd_list[cmd_size], src, src_size);
|
||||
|
||||
return RetryUntilSuccess([&]() { return I2cDriver::Send(session, cmd_list, src_size + cmd_size, static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop)); });
|
||||
}
|
||||
|
||||
Result Boot::WriteI2cRegister(I2cSessionImpl &session, const u8 address, const u8 value) {
|
||||
return Boot::WriteI2cRegister(session, &value, sizeof(value), &address, sizeof(address));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
90
stratosphere/boot/source/boot_pinmux_configuration.cpp
Normal file
90
stratosphere/boot/source/boot_pinmux_configuration.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_pinmux_map.hpp"
|
||||
#include "boot_pinmux_initial_configuration_icosa.hpp"
|
||||
#include "boot_pinmux_initial_configuration_copper.hpp"
|
||||
#include "boot_pinmux_initial_configuration_hoag.hpp"
|
||||
#include "boot_pinmux_initial_configuration_iowa.hpp"
|
||||
#include "boot_pinmux_initial_drive_pad_configuration.hpp"
|
||||
|
||||
void Boot::ConfigurePinmux() {
|
||||
/* Update parks. */
|
||||
for (size_t i = 0; i < PinmuxPadNameMax; i++) {
|
||||
Boot::PinmuxUpdatePark(static_cast<u32>(i));
|
||||
}
|
||||
|
||||
/* Set initial pad configs. */
|
||||
Boot::ConfigurePinmuxInitialPads();
|
||||
|
||||
/* Set initial drive pad configs. */
|
||||
Boot::ConfigurePinmuxInitialDrivePads();
|
||||
}
|
||||
|
||||
void Boot::ConfigurePinmuxInitialPads() {
|
||||
const PinmuxInitialConfig *configs = nullptr;
|
||||
size_t num_configs = 0;
|
||||
const HardwareType hw_type = Boot::GetHardwareType();
|
||||
|
||||
switch (hw_type) {
|
||||
case HardwareType_Icosa:
|
||||
configs = PinmuxInitialConfigsIcosa;
|
||||
num_configs = PinmuxNumInitialConfigsIcosa;
|
||||
break;
|
||||
case HardwareType_Copper:
|
||||
configs = PinmuxInitialConfigsCopper;
|
||||
num_configs = PinmuxNumInitialConfigsCopper;
|
||||
break;
|
||||
case HardwareType_Hoag:
|
||||
configs = PinmuxInitialConfigsHoag;
|
||||
num_configs = PinmuxNumInitialConfigsHoag;
|
||||
break;
|
||||
case HardwareType_Iowa:
|
||||
configs = PinmuxInitialConfigsIowa;
|
||||
num_configs = PinmuxNumInitialConfigsIowa;
|
||||
break;
|
||||
default:
|
||||
/* Unknown hardware type, we can't proceed. */
|
||||
std::abort();
|
||||
}
|
||||
|
||||
/* Ensure we found an appropriate config. */
|
||||
if (configs == nullptr) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_configs - 1; i++) {
|
||||
Boot::PinmuxUpdatePad(configs[i].name, configs[i].val, configs[i].mask);
|
||||
}
|
||||
|
||||
/* Extra configs for iowa only. */
|
||||
if (hw_type == HardwareType_Iowa) {
|
||||
static constexpr u32 ExtraIowaPinmuxPadNames[] = {
|
||||
0xAA, 0xAC, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(ExtraIowaPinmuxPadNames) / sizeof(ExtraIowaPinmuxPadNames[0]); i++) {
|
||||
Boot::PinmuxUpdatePad(ExtraIowaPinmuxPadNames[i], 0x2000, 0x2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::ConfigurePinmuxInitialDrivePads() {
|
||||
const PinmuxInitialConfig *configs = PinmuxInitialDrivePadConfigs;
|
||||
for (size_t i = 0; i < PinmuxNumInitialDrivePadConfigs; i++) {
|
||||
Boot::PinmuxUpdateDrivePad(configs[i].name, configs[i].val, configs[i].mask);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr PinmuxInitialConfig PinmuxInitialConfigsCopper[] = {
|
||||
{0x10, 0x20, 0x27F},
|
||||
{0x0F, 0x00, 0x267},
|
||||
{0x0E, 0x20, 0x27F},
|
||||
{0x5B, 0x00, 0x00},
|
||||
{0x80, 0x01, 0x7F},
|
||||
{0x34, 0x40, 0x267},
|
||||
{0x35, 0x40, 0x267},
|
||||
{0x55, 0x00, 0x18},
|
||||
{0x56, 0x01, 0x67},
|
||||
{0x5C, 0x00, 0x00},
|
||||
{0x59, 0x00, 0x00},
|
||||
{0x5A, 0x10, 0x18},
|
||||
{0x2C, 0x40, 0x267},
|
||||
{0x2D, 0x40, 0x267},
|
||||
{0x2E, 0x40, 0x267},
|
||||
{0x2F, 0x40, 0x267},
|
||||
{0x36, 0x00, 0x67},
|
||||
{0x37, 0x30, 0x7F},
|
||||
{0x38, 0x00, 0x67},
|
||||
{0x39, 0x28, 0x7F},
|
||||
{0x54, 0x00, 0x67},
|
||||
{0x9B, 0x30, 0x7F},
|
||||
{0x42, 0x00, 0x67},
|
||||
{0x43, 0x28, 0x7F},
|
||||
{0x44, 0x00, 0x67},
|
||||
{0x45, 0x28, 0x7F},
|
||||
{0x4B, 0x28, 0x7F},
|
||||
{0x4C, 0x00, 0x67},
|
||||
{0x4A, 0x00, 0x67},
|
||||
{0x4D, 0x00, 0x67},
|
||||
{0x64, 0x20, 0x27F},
|
||||
{0x63, 0x40, 0x267},
|
||||
{0x5E, 0x04, 0x67},
|
||||
{0x60, 0x04, 0x67},
|
||||
{0x17, 0x24, 0x7F},
|
||||
{0x18, 0x24, 0x7F},
|
||||
{0x27, 0x04, 0x67},
|
||||
{0x2A, 0x04, 0x67},
|
||||
{0x2B, 0x04, 0x67},
|
||||
{0x90, 0x24, 0x7F},
|
||||
{0x32, 0x24, 0x27F},
|
||||
{0x33, 0x34, 0x27F},
|
||||
{0x76, 0x04, 0x67},
|
||||
{0x79, 0x04, 0x67},
|
||||
{0x08, 0x24, 0x7F},
|
||||
{0x09, 0x24, 0x7F},
|
||||
{0x0A, 0x24, 0x7F},
|
||||
{0x0B, 0x24, 0x7F},
|
||||
{0x88, 0x34, 0x7F},
|
||||
{0x89, 0x24, 0x7F},
|
||||
{0x8A, 0x34, 0x7F},
|
||||
{0x8B, 0x34, 0x7F},
|
||||
{0x8D, 0x34, 0x7F},
|
||||
{0x81, 0x04, 0x67},
|
||||
{0x9D, 0x34, 0x7F},
|
||||
{0x9F, 0x34, 0x7F},
|
||||
{0xA1, 0x34, 0x7F},
|
||||
{0x92, 0x4C, 0x7F},
|
||||
{0x93, 0x4C, 0x7F},
|
||||
{0x94, 0x44, 0x7F},
|
||||
{0x96, 0x34, 0x7F},
|
||||
{0x98, 0x34, 0x7F},
|
||||
{0x99, 0x34, 0x7F},
|
||||
{0x12, 0x04, 0x7F},
|
||||
{0x13, 0x04, 0x67},
|
||||
{0x14, 0x04, 0x7F},
|
||||
{0x6A, 0x04, 0x67},
|
||||
{0x6B, 0x04, 0x67},
|
||||
{0x6C, 0x2C, 0x7F},
|
||||
{0x6D, 0x04, 0x67},
|
||||
{0x6E, 0x04, 0x67},
|
||||
{0x6F, 0x24, 0x7F},
|
||||
{0x70, 0x04, 0x7F},
|
||||
{0x73, 0x04, 0x67},
|
||||
{0x69, 0x24, 0x7F},
|
||||
{0x5D, 0x05, 0x07},
|
||||
{0x5F, 0x05, 0x07},
|
||||
{0x61, 0x05, 0x07},
|
||||
{0x47, 0x05, 0x07},
|
||||
{0x48, 0x05, 0x07},
|
||||
{0x46, 0x05, 0x07},
|
||||
{0x49, 0x05, 0x07},
|
||||
{0x19, 0x05, 0x07},
|
||||
{0x1A, 0x05, 0x07},
|
||||
{0x1B, 0x05, 0x07},
|
||||
{0x26, 0x05, 0x07},
|
||||
{0x28, 0x05, 0x07},
|
||||
{0x29, 0x05, 0x07},
|
||||
{0x8F, 0x05, 0x07},
|
||||
{0x30, 0x05, 0x07},
|
||||
{0x31, 0x05, 0x07},
|
||||
{0x52, 0x05, 0x07},
|
||||
{0x53, 0x05, 0x07},
|
||||
{0x75, 0x05, 0x07},
|
||||
{0x77, 0x05, 0x07},
|
||||
{0x78, 0x05, 0x07},
|
||||
{0x7A, 0x05, 0x07},
|
||||
{0x0D, 0x05, 0x07},
|
||||
{0x0C, 0x05, 0x07},
|
||||
{0x11, 0x05, 0x07},
|
||||
{0x8E, 0x05, 0x07},
|
||||
{0x00, 0x05, 0x07},
|
||||
{0x01, 0x05, 0x07},
|
||||
{0x05, 0x05, 0x07},
|
||||
{0x04, 0x05, 0x07},
|
||||
{0x03, 0x05, 0x07},
|
||||
{0x02, 0x05, 0x07},
|
||||
{0x06, 0x05, 0x07},
|
||||
{0x07, 0x05, 0x07},
|
||||
{0x87, 0x05, 0x07},
|
||||
{0x86, 0x05, 0x07},
|
||||
{0x82, 0x05, 0x07},
|
||||
{0x83, 0x05, 0x07},
|
||||
{0x85, 0x05, 0x07},
|
||||
{0x84, 0x05, 0x07},
|
||||
{0x8C, 0x05, 0x07},
|
||||
{0x7B, 0x05, 0x07},
|
||||
{0x7C, 0x05, 0x07},
|
||||
{0x7D, 0x05, 0x07},
|
||||
{0x7E, 0x05, 0x07},
|
||||
{0x7F, 0x05, 0x07},
|
||||
{0x9C, 0x05, 0x07},
|
||||
{0x9E, 0x05, 0x07},
|
||||
{0xA0, 0x05, 0x07},
|
||||
{0x58, 0x00, 0x00},
|
||||
{0x4F, 0x05, 0x07},
|
||||
{0x50, 0x05, 0x07},
|
||||
{0x4E, 0x05, 0x07},
|
||||
{0x51, 0x05, 0x07},
|
||||
{0x3A, 0x05, 0x07},
|
||||
{0x3B, 0x05, 0x07},
|
||||
{0x3C, 0x05, 0x07},
|
||||
{0x3D, 0x05, 0x07},
|
||||
{0x95, 0x05, 0x07},
|
||||
{0x97, 0x05, 0x07},
|
||||
{0x9A, 0x05, 0x07},
|
||||
{0x15, 0x05, 0x07},
|
||||
{0x16, 0x05, 0x07},
|
||||
{0x1C, 0x05, 0x07},
|
||||
{0x1D, 0x05, 0x07},
|
||||
{0x1E, 0x05, 0x07},
|
||||
{0x1F, 0x05, 0x07},
|
||||
{0x3E, 0x05, 0x07},
|
||||
{0x3F, 0x05, 0x07},
|
||||
{0x40, 0x05, 0x07},
|
||||
{0x41, 0x05, 0x07},
|
||||
{0x91, 0x05, 0x07},
|
||||
{0x71, 0x05, 0x07},
|
||||
{0x72, 0x05, 0x07},
|
||||
{0x74, 0x05, 0x07},
|
||||
{0x22, 0x05, 0x07},
|
||||
{0x23, 0x05, 0x07},
|
||||
{0x20, 0x05, 0x07},
|
||||
{0x21, 0x05, 0x07},
|
||||
{0x24, 0x05, 0x07},
|
||||
{0x25, 0x05, 0x07},
|
||||
{0x62, 0x05, 0x07},
|
||||
{0x65, 0x05, 0x07},
|
||||
{0x66, 0x05, 0x07},
|
||||
{0x67, 0x05, 0x07},
|
||||
{0x68, 0x05, 0x07},
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxNumInitialConfigsCopper = (sizeof(PinmuxInitialConfigsCopper) / sizeof(PinmuxInitialConfigsCopper[0]));
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr PinmuxInitialConfig PinmuxInitialConfigsHoag[] = {
|
||||
{0x5D, 0x00, 0x67},
|
||||
{0x47, 0x28, 0x7F},
|
||||
{0x48, 0x00, 0x67},
|
||||
{0x46, 0x00, 0x67},
|
||||
{0x49, 0x00, 0x67},
|
||||
{0x30, 0x40, 0x27F},
|
||||
{0x31, 0x40, 0x27F},
|
||||
{0x0D, 0x20, 0x27F},
|
||||
{0x0C, 0x00, 0x267},
|
||||
{0x10, 0x20, 0x27F},
|
||||
{0x0F, 0x00, 0x267},
|
||||
{0x0E, 0x20, 0x27F},
|
||||
{0x00, 0x48, 0x7F},
|
||||
{0x01, 0x50, 0x7F},
|
||||
{0x05, 0x50, 0x7F},
|
||||
{0x04, 0x50, 0x7F},
|
||||
{0x03, 0x50, 0x7F},
|
||||
{0x02, 0x50, 0x7F},
|
||||
{0x5B, 0x00, 0x78},
|
||||
{0x7C, 0x01, 0x67},
|
||||
{0x80, 0x01, 0x7F},
|
||||
{0x34, 0x40, 0x27F},
|
||||
{0x35, 0x40, 0x27F},
|
||||
{0x55, 0x20, 0x78},
|
||||
{0x56, 0x20, 0x7F},
|
||||
{0xA1, 0x30, 0x7F},
|
||||
{0x5C, 0x00, 0x78},
|
||||
{0x59, 0x00, 0x60},
|
||||
{0x5A, 0x30, 0x78},
|
||||
{0x2C, 0x40, 0x27F},
|
||||
{0x2D, 0x40, 0x27F},
|
||||
{0x2E, 0x40, 0x27F},
|
||||
{0x2F, 0x40, 0x27F},
|
||||
{0x3B, 0x20, 0x7F},
|
||||
{0x3C, 0x00, 0x67},
|
||||
{0x3D, 0x20, 0x7F},
|
||||
{0x36, 0x00, 0x67},
|
||||
{0x37, 0x30, 0x7F},
|
||||
{0x38, 0x00, 0x67},
|
||||
{0x39, 0x28, 0x7F},
|
||||
{0x54, 0x00, 0x67},
|
||||
{0x9B, 0x30, 0x7F},
|
||||
{0x1C, 0x00, 0x67},
|
||||
{0x1D, 0x30, 0x7F},
|
||||
{0x1E, 0x00, 0x67},
|
||||
{0x1F, 0x00, 0x67},
|
||||
{0x3F, 0x20, 0x7F},
|
||||
{0x40, 0x00, 0x67},
|
||||
{0x41, 0x20, 0x7F},
|
||||
{0x42, 0x00, 0x67},
|
||||
{0x43, 0x28, 0x7F},
|
||||
{0x44, 0x00, 0x67},
|
||||
{0x45, 0x28, 0x7F},
|
||||
{0x22, 0x00, 0x67},
|
||||
{0x23, 0x28, 0x7F},
|
||||
{0x20, 0x00, 0x67},
|
||||
{0x21, 0x00, 0x67},
|
||||
{0x4B, 0x28, 0x7F},
|
||||
{0x4C, 0x00, 0x67},
|
||||
{0x4A, 0x00, 0x67},
|
||||
{0x4D, 0x00, 0x67},
|
||||
{0x64, 0x20, 0x27F},
|
||||
{0x5F, 0x34, 0x7F},
|
||||
{0x60, 0x04, 0x67},
|
||||
{0x61, 0x2C, 0x7F},
|
||||
{0x2A, 0x04, 0x67},
|
||||
{0x2B, 0x04, 0x67},
|
||||
{0x8F, 0x24, 0x7F},
|
||||
{0x33, 0x34, 0x27F},
|
||||
{0x52, 0x2C, 0x7F},
|
||||
{0x53, 0x24, 0x7F},
|
||||
{0x77, 0x04, 0x67},
|
||||
{0x78, 0x34, 0x7F},
|
||||
{0x11, 0x04, 0x67},
|
||||
{0x06, 0x2C, 0x7F},
|
||||
{0x08, 0x24, 0x7F},
|
||||
{0x09, 0x24, 0x7F},
|
||||
{0x0A, 0x24, 0x7F},
|
||||
{0x0B, 0x24, 0x7F},
|
||||
{0x88, 0x34, 0x7F},
|
||||
{0x86, 0x2C, 0x7F},
|
||||
{0x82, 0x24, 0x7F},
|
||||
{0x85, 0x34, 0x7F},
|
||||
{0x89, 0x24, 0x7F},
|
||||
{0x8A, 0x34, 0x7F},
|
||||
{0x8B, 0x34, 0x7F},
|
||||
{0x8C, 0x34, 0x7F},
|
||||
{0x8D, 0x24, 0x7F},
|
||||
{0x7D, 0x04, 0x67},
|
||||
{0x7E, 0x04, 0x67},
|
||||
{0x81, 0x04, 0x67},
|
||||
{0x9C, 0x34, 0x7F},
|
||||
{0x9D, 0x34, 0x7F},
|
||||
{0x9E, 0x2C, 0x7F},
|
||||
{0x9F, 0x34, 0x7F},
|
||||
{0xA0, 0x04, 0x67},
|
||||
{0x4F, 0x04, 0x67},
|
||||
{0x51, 0x04, 0x67},
|
||||
{0x3A, 0x24, 0x7F},
|
||||
{0x92, 0x4C, 0x7F},
|
||||
{0x93, 0x4C, 0x7F},
|
||||
{0x94, 0x44, 0x7F},
|
||||
{0x95, 0x04, 0x67},
|
||||
{0x96, 0x34, 0x7F},
|
||||
{0x97, 0x04, 0x67},
|
||||
{0x98, 0x34, 0x7F},
|
||||
{0x99, 0x34, 0x7F},
|
||||
{0x9A, 0x04, 0x67},
|
||||
{0x3E, 0x24, 0x7F},
|
||||
{0x6A, 0x04, 0x67},
|
||||
{0x6B, 0x04, 0x67},
|
||||
{0x6C, 0x2C, 0x7F},
|
||||
{0x6D, 0x04, 0x67},
|
||||
{0x6E, 0x04, 0x67},
|
||||
{0x6F, 0x24, 0x7F},
|
||||
{0x91, 0x24, 0x7F},
|
||||
{0x70, 0x04, 0x7F},
|
||||
{0x71, 0x04, 0x67},
|
||||
{0x72, 0x04, 0x67},
|
||||
{0x65, 0x34, 0x7F},
|
||||
{0x66, 0x04, 0x67},
|
||||
{0x67, 0x04, 0x267},
|
||||
{0x5E, 0x05, 0x07},
|
||||
{0x17, 0x05, 0x07},
|
||||
{0x18, 0x05, 0x07},
|
||||
{0x19, 0x05, 0x07},
|
||||
{0x1A, 0x05, 0x07},
|
||||
{0x1B, 0x05, 0x07},
|
||||
{0x26, 0x05, 0x07},
|
||||
{0x27, 0x05, 0x07},
|
||||
{0x28, 0x05, 0x07},
|
||||
{0x29, 0x05, 0x07},
|
||||
{0x90, 0x05, 0x07},
|
||||
{0x32, 0x05, 0x07},
|
||||
{0x75, 0x05, 0x07},
|
||||
{0x76, 0x05, 0x07},
|
||||
{0x79, 0x05, 0x07},
|
||||
{0x7A, 0x05, 0x07},
|
||||
{0x8E, 0x05, 0x07},
|
||||
{0x07, 0x05, 0x07},
|
||||
{0x87, 0x05, 0x07},
|
||||
{0x83, 0x05, 0x07},
|
||||
{0x84, 0x05, 0x07},
|
||||
{0x7B, 0x05, 0x07},
|
||||
{0x7F, 0x05, 0x07},
|
||||
{0x58, 0x00, 0x00},
|
||||
{0x50, 0x05, 0x07},
|
||||
{0x4E, 0x05, 0x07},
|
||||
{0x12, 0x05, 0x07},
|
||||
{0x13, 0x05, 0x07},
|
||||
{0x14, 0x05, 0x07},
|
||||
{0x15, 0x05, 0x07},
|
||||
{0x16, 0x05, 0x07},
|
||||
{0x73, 0x05, 0x07},
|
||||
{0x74, 0x05, 0x07},
|
||||
{0x24, 0x05, 0x07},
|
||||
{0x25, 0x05, 0x07},
|
||||
{0x62, 0x05, 0x07},
|
||||
{0x68, 0x05, 0x07},
|
||||
{0x69, 0x05, 0x07},
|
||||
{0x63, 0x05, 0x07},
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxNumInitialConfigsHoag = (sizeof(PinmuxInitialConfigsHoag) / sizeof(PinmuxInitialConfigsHoag[0]));
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr PinmuxInitialConfig PinmuxInitialConfigsIcosa[] = {
|
||||
{0x5D, 0x00, 0x67},
|
||||
{0x47, 0x28, 0x7F},
|
||||
{0x48, 0x00, 0x67},
|
||||
{0x46, 0x00, 0x67},
|
||||
{0x49, 0x00, 0x67},
|
||||
{0x30, 0x40, 0x27F},
|
||||
{0x31, 0x40, 0x27F},
|
||||
{0x0D, 0x20, 0x27F},
|
||||
{0x0C, 0x00, 0x267},
|
||||
{0x10, 0x20, 0x27F},
|
||||
{0x0F, 0x00, 0x267},
|
||||
{0x0E, 0x20, 0x27F},
|
||||
{0x00, 0x48, 0x7F},
|
||||
{0x01, 0x50, 0x7F},
|
||||
{0x05, 0x50, 0x7F},
|
||||
{0x04, 0x50, 0x7F},
|
||||
{0x03, 0x50, 0x7F},
|
||||
{0x02, 0x50, 0x7F},
|
||||
{0x5B, 0x00, 0x78},
|
||||
{0x7C, 0x01, 0x67},
|
||||
{0x80, 0x01, 0x7F},
|
||||
{0x34, 0x40, 0x27F},
|
||||
{0x35, 0x40, 0x27F},
|
||||
{0x55, 0x20, 0x78},
|
||||
{0x56, 0x20, 0x7F},
|
||||
{0xA1, 0x30, 0x7F},
|
||||
{0x5C, 0x00, 0x78},
|
||||
{0x59, 0x00, 0x60},
|
||||
{0x5A, 0x30, 0x78},
|
||||
{0x2C, 0x40, 0x27F},
|
||||
{0x2D, 0x40, 0x27F},
|
||||
{0x2E, 0x40, 0x27F},
|
||||
{0x2F, 0x40, 0x27F},
|
||||
{0x3B, 0x20, 0x7F},
|
||||
{0x3C, 0x00, 0x67},
|
||||
{0x3D, 0x20, 0x7F},
|
||||
{0x36, 0x00, 0x67},
|
||||
{0x37, 0x30, 0x7F},
|
||||
{0x38, 0x00, 0x67},
|
||||
{0x39, 0x28, 0x7F},
|
||||
{0x54, 0x00, 0x67},
|
||||
{0x9B, 0x30, 0x7F},
|
||||
{0x1C, 0x00, 0x67},
|
||||
{0x1D, 0x30, 0x7F},
|
||||
{0x1E, 0x00, 0x67},
|
||||
{0x1F, 0x00, 0x67},
|
||||
{0x3F, 0x20, 0x7F},
|
||||
{0x40, 0x00, 0x67},
|
||||
{0x41, 0x20, 0x7F},
|
||||
{0x42, 0x00, 0x67},
|
||||
{0x43, 0x28, 0x7F},
|
||||
{0x44, 0x00, 0x67},
|
||||
{0x45, 0x28, 0x7F},
|
||||
{0x22, 0x00, 0x67},
|
||||
{0x23, 0x28, 0x7F},
|
||||
{0x20, 0x00, 0x67},
|
||||
{0x21, 0x00, 0x67},
|
||||
{0x4B, 0x28, 0x7F},
|
||||
{0x4C, 0x00, 0x67},
|
||||
{0x4A, 0x00, 0x67},
|
||||
{0x4D, 0x00, 0x67},
|
||||
{0x64, 0x20, 0x27F},
|
||||
{0x5F, 0x34, 0x7F},
|
||||
{0x60, 0x04, 0x67},
|
||||
{0x61, 0x2C, 0x7F},
|
||||
{0x2A, 0x04, 0x67},
|
||||
{0x2B, 0x04, 0x67},
|
||||
{0x8F, 0x24, 0x7F},
|
||||
{0x33, 0x34, 0x27F},
|
||||
{0x52, 0x2C, 0x7F},
|
||||
{0x53, 0x24, 0x7F},
|
||||
{0x77, 0x04, 0x67},
|
||||
{0x78, 0x34, 0x7F},
|
||||
{0x11, 0x04, 0x67},
|
||||
{0x06, 0x2C, 0x7F},
|
||||
{0x08, 0x24, 0x7F},
|
||||
{0x09, 0x24, 0x7F},
|
||||
{0x0A, 0x24, 0x7F},
|
||||
{0x0B, 0x24, 0x7F},
|
||||
{0x88, 0x34, 0x7F},
|
||||
{0x86, 0x2C, 0x7F},
|
||||
{0x82, 0x24, 0x7F},
|
||||
{0x85, 0x34, 0x7F},
|
||||
{0x89, 0x24, 0x7F},
|
||||
{0x8A, 0x34, 0x7F},
|
||||
{0x8B, 0x34, 0x7F},
|
||||
{0x8C, 0x34, 0x7F},
|
||||
{0x8D, 0x24, 0x7F},
|
||||
{0x7D, 0x04, 0x67},
|
||||
{0x7E, 0x04, 0x67},
|
||||
{0x81, 0x04, 0x67},
|
||||
{0x9C, 0x34, 0x7F},
|
||||
{0x9D, 0x34, 0x7F},
|
||||
{0x9E, 0x2C, 0x7F},
|
||||
{0x9F, 0x34, 0x7F},
|
||||
{0xA0, 0x04, 0x67},
|
||||
{0x4F, 0x04, 0x67},
|
||||
{0x51, 0x04, 0x67},
|
||||
{0x3A, 0x24, 0x7F},
|
||||
{0x92, 0x4C, 0x7F},
|
||||
{0x93, 0x4C, 0x7F},
|
||||
{0x94, 0x44, 0x7F},
|
||||
{0x95, 0x04, 0x67},
|
||||
{0x96, 0x34, 0x7F},
|
||||
{0x97, 0x04, 0x67},
|
||||
{0x98, 0x34, 0x7F},
|
||||
{0x99, 0x34, 0x7F},
|
||||
{0x9A, 0x04, 0x67},
|
||||
{0x3E, 0x24, 0x7F},
|
||||
{0x6A, 0x04, 0x67},
|
||||
{0x6B, 0x04, 0x67},
|
||||
{0x6C, 0x2C, 0x7F},
|
||||
{0x6D, 0x04, 0x67},
|
||||
{0x6E, 0x04, 0x67},
|
||||
{0x6F, 0x24, 0x7F},
|
||||
{0x91, 0x24, 0x7F},
|
||||
{0x70, 0x04, 0x7F},
|
||||
{0x71, 0x04, 0x67},
|
||||
{0x72, 0x04, 0x67},
|
||||
{0x65, 0x34, 0x7F},
|
||||
{0x66, 0x04, 0x67},
|
||||
{0x67, 0x04, 0x267},
|
||||
{0x5E, 0x05, 0x07},
|
||||
{0x17, 0x05, 0x07},
|
||||
{0x18, 0x05, 0x07},
|
||||
{0x19, 0x05, 0x07},
|
||||
{0x1A, 0x05, 0x07},
|
||||
{0x1B, 0x05, 0x07},
|
||||
{0x26, 0x05, 0x07},
|
||||
{0x27, 0x05, 0x07},
|
||||
{0x28, 0x05, 0x07},
|
||||
{0x29, 0x05, 0x07},
|
||||
{0x90, 0x05, 0x07},
|
||||
{0x32, 0x05, 0x07},
|
||||
{0x75, 0x05, 0x07},
|
||||
{0x76, 0x05, 0x07},
|
||||
{0x79, 0x05, 0x07},
|
||||
{0x7A, 0x05, 0x07},
|
||||
{0x8E, 0x05, 0x07},
|
||||
{0x07, 0x05, 0x07},
|
||||
{0x87, 0x05, 0x07},
|
||||
{0x83, 0x05, 0x07},
|
||||
{0x84, 0x05, 0x07},
|
||||
{0x7B, 0x05, 0x07},
|
||||
{0x7F, 0x05, 0x07},
|
||||
{0x58, 0x00, 0x00},
|
||||
{0x50, 0x05, 0x07},
|
||||
{0x4E, 0x05, 0x07},
|
||||
{0x12, 0x05, 0x07},
|
||||
{0x13, 0x05, 0x07},
|
||||
{0x14, 0x05, 0x07},
|
||||
{0x15, 0x05, 0x07},
|
||||
{0x16, 0x05, 0x07},
|
||||
{0x73, 0x05, 0x07},
|
||||
{0x74, 0x05, 0x07},
|
||||
{0x24, 0x05, 0x07},
|
||||
{0x25, 0x05, 0x07},
|
||||
{0x62, 0x05, 0x07},
|
||||
{0x68, 0x05, 0x07},
|
||||
{0x69, 0x05, 0x07},
|
||||
{0x63, 0x05, 0x07},
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxNumInitialConfigsIcosa = (sizeof(PinmuxInitialConfigsIcosa) / sizeof(PinmuxInitialConfigsIcosa[0]));
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr PinmuxInitialConfig PinmuxInitialConfigsIowa[] = {
|
||||
{0x5D, 0x00, 0x7F},
|
||||
{0x47, 0x28, 0x7F},
|
||||
{0x48, 0x00, 0x7F},
|
||||
{0x46, 0x00, 0x7F},
|
||||
{0x49, 0x00, 0x7F},
|
||||
{0x30, 0x40, 0x27F},
|
||||
{0x31, 0x40, 0x27F},
|
||||
{0x0D, 0x20, 0x27F},
|
||||
{0x0C, 0x00, 0x27F},
|
||||
{0x10, 0x40, 0x27F},
|
||||
{0x0F, 0x00, 0x27F},
|
||||
{0x0E, 0x20, 0x27F},
|
||||
{0x00, 0x40, 0x7F},
|
||||
{0x01, 0x50, 0x7F},
|
||||
{0x05, 0x50, 0x7F},
|
||||
{0x04, 0x50, 0x7F},
|
||||
{0x03, 0x50, 0x7F},
|
||||
{0x02, 0x50, 0x7F},
|
||||
{0xAA, 0x40, 0x7F},
|
||||
{0xAC, 0x40, 0x7F},
|
||||
{0xA2, 0x50, 0x7F},
|
||||
{0xA3, 0x50, 0x7F},
|
||||
{0xA4, 0x50, 0x7F},
|
||||
{0xA5, 0x50, 0x7F},
|
||||
{0xA6, 0x50, 0x7F},
|
||||
{0xA7, 0x50, 0x7F},
|
||||
{0xA8, 0x50, 0x7F},
|
||||
{0xA9, 0x50, 0x7F},
|
||||
{0x5B, 0x00, 0x78},
|
||||
{0x7C, 0x01, 0x67},
|
||||
{0x80, 0x01, 0x7F},
|
||||
{0x34, 0x40, 0x27F},
|
||||
{0x35, 0x40, 0x27F},
|
||||
{0x55, 0x20, 0x78},
|
||||
{0x56, 0x20, 0x7F},
|
||||
{0xA1, 0x30, 0x7F},
|
||||
{0x5C, 0x00, 0x78},
|
||||
{0x5A, 0x20, 0x78},
|
||||
{0x2C, 0x40, 0x27F},
|
||||
{0x2D, 0x40, 0x27F},
|
||||
{0x2E, 0x40, 0x27F},
|
||||
{0x2F, 0x40, 0x27F},
|
||||
{0x3B, 0x20, 0x7F},
|
||||
{0x3C, 0x00, 0x7F},
|
||||
{0x3D, 0x20, 0x7F},
|
||||
{0x36, 0x00, 0x7F},
|
||||
{0x37, 0x30, 0x7F},
|
||||
{0x38, 0x00, 0x7F},
|
||||
{0x39, 0x28, 0x7F},
|
||||
{0x54, 0x00, 0x67},
|
||||
{0x9B, 0x30, 0x7F},
|
||||
{0x1C, 0x00, 0x7F},
|
||||
{0x1D, 0x30, 0x7F},
|
||||
{0x1E, 0x00, 0x7F},
|
||||
{0x1F, 0x00, 0x7F},
|
||||
{0x3F, 0x20, 0x7F},
|
||||
{0x40, 0x00, 0x7F},
|
||||
{0x41, 0x20, 0x7F},
|
||||
{0x42, 0x00, 0x7F},
|
||||
{0x43, 0x28, 0x7F},
|
||||
{0x44, 0x00, 0x7F},
|
||||
{0x45, 0x28, 0x7F},
|
||||
{0x4B, 0x28, 0x7F},
|
||||
{0x4C, 0x00, 0x7F},
|
||||
{0x4A, 0x00, 0x7F},
|
||||
{0x4D, 0x00, 0x7F},
|
||||
{0x64, 0x20, 0x27F},
|
||||
{0x5F, 0x34, 0x7F},
|
||||
{0x60, 0x04, 0x67},
|
||||
{0x61, 0x2C, 0x7F},
|
||||
{0x2A, 0x04, 0x67},
|
||||
{0x8F, 0x24, 0x7F},
|
||||
{0x33, 0x34, 0x27F},
|
||||
{0x52, 0x2C, 0x7F},
|
||||
{0x53, 0x24, 0x7F},
|
||||
{0x77, 0x04, 0x67},
|
||||
{0x78, 0x24, 0x7F},
|
||||
{0x11, 0x04, 0x67},
|
||||
{0x06, 0x2C, 0x7F},
|
||||
{0x08, 0x24, 0x7F},
|
||||
{0x09, 0x24, 0x7F},
|
||||
{0x0A, 0x24, 0x7F},
|
||||
{0x0B, 0x24, 0x7F},
|
||||
{0x88, 0x34, 0x7F},
|
||||
{0x86, 0x2C, 0x7F},
|
||||
{0x82, 0x24, 0x7F},
|
||||
{0x85, 0x34, 0x7F},
|
||||
{0x89, 0x24, 0x7F},
|
||||
{0x8A, 0x34, 0x7F},
|
||||
{0x8B, 0x34, 0x7F},
|
||||
{0x8C, 0x24, 0x7F},
|
||||
{0x8D, 0x24, 0x7F},
|
||||
{0x7D, 0x04, 0x67},
|
||||
{0x7E, 0x04, 0x67},
|
||||
{0x81, 0x04, 0x67},
|
||||
{0x9C, 0x24, 0x7F},
|
||||
{0x9D, 0x34, 0x7F},
|
||||
{0x9E, 0x2C, 0x7F},
|
||||
{0x9F, 0x34, 0x7F},
|
||||
{0xA0, 0x04, 0x67},
|
||||
{0x4F, 0x04, 0x67},
|
||||
{0x51, 0x04, 0x67},
|
||||
{0x3A, 0x24, 0x7F},
|
||||
{0x92, 0x4C, 0x7F},
|
||||
{0x93, 0x4C, 0x7F},
|
||||
{0x94, 0x44, 0x7F},
|
||||
{0x95, 0x04, 0x67},
|
||||
{0x96, 0x34, 0x7F},
|
||||
{0x97, 0x04, 0x67},
|
||||
{0x98, 0x34, 0x7F},
|
||||
{0x9A, 0x04, 0x67},
|
||||
{0x3E, 0x24, 0x7F},
|
||||
{0x6A, 0x04, 0x67},
|
||||
{0x6B, 0x04, 0x67},
|
||||
{0x6C, 0x2C, 0x7F},
|
||||
{0x6D, 0x04, 0x67},
|
||||
{0x6E, 0x04, 0x67},
|
||||
{0x6F, 0x24, 0x7F},
|
||||
{0x91, 0x24, 0x7F},
|
||||
{0x70, 0x04, 0x7F},
|
||||
{0x71, 0x04, 0x67},
|
||||
{0x72, 0x04, 0x67},
|
||||
{0x65, 0x34, 0x7F},
|
||||
{0x66, 0x04, 0x67},
|
||||
{0x67, 0x04, 0x267},
|
||||
{0x5E, 0x05, 0x07},
|
||||
{0x17, 0x05, 0x07},
|
||||
{0x18, 0x05, 0x07},
|
||||
{0x19, 0x05, 0x07},
|
||||
{0x1A, 0x05, 0x07},
|
||||
{0x1B, 0x05, 0x07},
|
||||
{0x26, 0x05, 0x07},
|
||||
{0x27, 0x05, 0x07},
|
||||
{0x28, 0x05, 0x07},
|
||||
{0x29, 0x05, 0x07},
|
||||
{0x2B, 0x05, 0x07},
|
||||
{0x90, 0x05, 0x07},
|
||||
{0x32, 0x05, 0x07},
|
||||
{0x75, 0x05, 0x07},
|
||||
{0x76, 0x05, 0x07},
|
||||
{0x79, 0x05, 0x07},
|
||||
{0x7A, 0x05, 0x07},
|
||||
{0x8E, 0x05, 0x07},
|
||||
{0xAB, 0x05, 0x07},
|
||||
{0xAD, 0x05, 0x07},
|
||||
{0xAE, 0x05, 0x07},
|
||||
{0x07, 0x05, 0x07},
|
||||
{0x87, 0x05, 0x07},
|
||||
{0x83, 0x05, 0x07},
|
||||
{0x84, 0x05, 0x07},
|
||||
{0x7B, 0x05, 0x07},
|
||||
{0x7F, 0x05, 0x07},
|
||||
{0x58, 0x00, 0x00},
|
||||
{0x59, 0x00, 0x00},
|
||||
{0x50, 0x05, 0x07},
|
||||
{0x4E, 0x05, 0x07},
|
||||
{0x99, 0x05, 0x07},
|
||||
{0x12, 0x05, 0x07},
|
||||
{0x13, 0x05, 0x07},
|
||||
{0x14, 0x05, 0x07},
|
||||
{0x15, 0x05, 0x07},
|
||||
{0x16, 0x05, 0x07},
|
||||
{0x73, 0x05, 0x07},
|
||||
{0x74, 0x05, 0x07},
|
||||
{0x22, 0x05, 0x07},
|
||||
{0x23, 0x05, 0x07},
|
||||
{0x20, 0x05, 0x07},
|
||||
{0x21, 0x05, 0x07},
|
||||
{0x24, 0x05, 0x07},
|
||||
{0x25, 0x05, 0x07},
|
||||
{0x62, 0x05, 0x07},
|
||||
{0x68, 0x05, 0x07},
|
||||
{0x69, 0x05, 0x07},
|
||||
{0x63, 0x05, 0x07},
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxNumInitialConfigsIowa = (sizeof(PinmuxInitialConfigsIowa) / sizeof(PinmuxInitialConfigsIowa[0]));
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "boot_types.hpp"
|
||||
|
||||
static constexpr PinmuxInitialConfig PinmuxInitialDrivePadConfigs[] = {
|
||||
{0x04, 0x01010000, 0x01F1F000},
|
||||
{0x0D, 0x01010000, 0x01F1F000},
|
||||
{0x10, 0x01010000, 0x01F1F000},
|
||||
{0x12, 0x01010000, 0x01F1F000},
|
||||
{0x13, 0x01010000, 0x01F1F000},
|
||||
{0x14, 0x0001F000, 0x01F1F000},
|
||||
{0x15, 0x0001F000, 0x01F1F000},
|
||||
{0x24, 0x01010000, 0x01F1F000},
|
||||
{0x25, 0x01010000, 0x01F1F000},
|
||||
{0x26, 0x01010000, 0x01F1F000},
|
||||
{0x27, 0x01010000, 0x01F1F000},
|
||||
{0x28, 0x01010000, 0x01F1F000},
|
||||
{0x29, 0x01010000, 0x01F1F000},
|
||||
{0x2A, 0x01010000, 0x01F1F000},
|
||||
{0x2B, 0x01010000, 0x01F1F000},
|
||||
{0x2C, 0x01F1F000, 0x01F1F000},
|
||||
{0x2D, 0x01F1F000, 0x01F1F000},
|
||||
{0x2F, 0x01F1F000, 0x01F1F000},
|
||||
{0x30, 0x01404000, 0x01F1F000},
|
||||
{0x31, 0x0001F000, 0x01F1F000},
|
||||
{0x32, 0x0001F000, 0x01F1F000},
|
||||
{0x33, 0x0001F000, 0x01F1F000},
|
||||
{0x34, 0x0001F000, 0x01F1F000},
|
||||
{0x35, 0x00007000, 0x01F1F000},
|
||||
{0x36, 0x00007000, 0x01F1F000},
|
||||
{0x46, 0x01010000, 0x01F1F000},
|
||||
{0x47, 0x01010000, 0x01F1F000},
|
||||
{0x4C, 0x01404000, 0x01F1F000},
|
||||
{0x4D, 0x01404000, 0x01F1F000},
|
||||
{0x62, 0x0001F000, 0x01F1F000},
|
||||
{0x63, 0x0001F000, 0x01F1F000},
|
||||
{0x7C, 0x01414000, 0x01F1F000},
|
||||
{0x87, 0x01404000, 0x01F1F000},
|
||||
{0x88, 0x01404000, 0x01F1F000},
|
||||
{0x89, 0x01404000, 0x01F1F000},
|
||||
{0x8A, 0x01404000, 0x01F1F000},
|
||||
{0x6D, 0x00000000, 0xF0000000},
|
||||
{0x6E, 0x00000000, 0xF0000000},
|
||||
{0x6F, 0x00000000, 0xF0000000},
|
||||
{0x70, 0x00000000, 0xF0000000},
|
||||
{0x71, 0x00000000, 0xF0000000},
|
||||
{0x72, 0x00000000, 0xF0000000},
|
||||
{0x73, 0x00000000, 0xF0000000},
|
||||
{0x74, 0x00000000, 0xF0000000},
|
||||
{0x75, 0x00000000, 0xF0000000},
|
||||
{0x76, 0x00000000, 0xF0000000},
|
||||
{0x69, 0x51212000, 0xF1F1F000},
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxNumInitialDrivePadConfigs = (sizeof(PinmuxInitialDrivePadConfigs) / sizeof(PinmuxInitialDrivePadConfigs[0]));
|
||||
364
stratosphere/boot/source/boot_pinmux_map.hpp
Normal file
364
stratosphere/boot/source/boot_pinmux_map.hpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
struct PinmuxDefinition {
|
||||
u32 reg_offset;
|
||||
u32 mask_val;
|
||||
u32 pm_val;
|
||||
};
|
||||
|
||||
struct PinmuxDrivePadDefinition {
|
||||
u32 reg_offset;
|
||||
u32 mask_val;
|
||||
};
|
||||
|
||||
static constexpr PinmuxDefinition PinmuxMap[] = {
|
||||
{0x00003000, 0x72FF, 0x01}, /* Sdmmc1Clk */
|
||||
{0x00003004, 0x72FF, 0x02}, /* Sdmmc1Cmd */
|
||||
{0x00003008, 0x72FF, 0x02}, /* Sdmmc1Dat3 */
|
||||
{0x0000300C, 0x72FF, 0x02}, /* Sdmmc1Dat2 */
|
||||
{0x00003010, 0x72FF, 0x02}, /* Sdmmc1Dat1 */
|
||||
{0x00003014, 0x72FF, 0x01}, /* Sdmmc1Dat0 */
|
||||
{0x0000301C, 0x72FF, 0x01}, /* Sdmmc3Clk */
|
||||
{0x00003020, 0x72FF, 0x01}, /* Sdmmc3Cmd */
|
||||
{0x00003024, 0x72FF, 0x01}, /* Sdmmc3Dat0 */
|
||||
{0x00003028, 0x72FF, 0x01}, /* Sdmmc3Dat1 */
|
||||
{0x0000302C, 0x72FF, 0x01}, /* Sdmmc3Dat2 */
|
||||
{0x00003030, 0x72FF, 0x01}, /* Sdmmc3Dat3 */
|
||||
{0x00003038, 0x1DFF, 0x01}, /* PexL0RstN */
|
||||
{0x0000303C, 0x1DFF, 0x01}, /* PexL0ClkreqN */
|
||||
{0x00003040, 0x1DFF, 0x01}, /* PexWakeN */
|
||||
{0x00003044, 0x1DFF, 0x01}, /* PexL1RstN */
|
||||
{0x00003048, 0x1DFF, 0x01}, /* PexL1ClkreqN */
|
||||
{0x0000304C, 0x19FF, 0x01}, /* SataLedActive */
|
||||
{0x00003050, 0x1F2FF, 0x01}, /* Spi1Mosi */
|
||||
{0x00003054, 0x1F2FF, 0x01}, /* Spi1Miso */
|
||||
{0x00003058, 0x1F2FF, 0x01}, /* Spi1Sck */
|
||||
{0x0000305C, 0x1F2FF, 0x01}, /* Spi1Cs0 */
|
||||
{0x00003060, 0x1F2FF, 0x01}, /* Spi1Cs1 */
|
||||
{0x00003064, 0x72FF, 0x02}, /* Spi2Mosi */
|
||||
{0x00003068, 0x72FF, 0x02}, /* Spi2Miso */
|
||||
{0x0000306C, 0x72FF, 0x02}, /* Spi2Sck */
|
||||
{0x00003070, 0x72FF, 0x02}, /* Spi2Cs0 */
|
||||
{0x00003074, 0x72FF, 0x01}, /* Spi2Cs1 */
|
||||
{0x00003078, 0x1F2FF, 0x01}, /* Spi4Mosi */
|
||||
{0x0000307C, 0x1F2FF, 0x01}, /* Spi4Miso */
|
||||
{0x00003080, 0x1F2FF, 0x01}, /* Spi4Sck */
|
||||
{0x00003084, 0x1F2FF, 0x01}, /* Spi4Cs0 */
|
||||
{0x00003088, 0x72FF, 0x01}, /* QspiSck */
|
||||
{0x0000308C, 0x72FF, 0x01}, /* QspiCsN */
|
||||
{0x00003090, 0x72FF, 0x01}, /* QspiIo0 */
|
||||
{0x00003094, 0x72FF, 0x01}, /* QspiIo1 */
|
||||
{0x00003098, 0x72FF, 0x01}, /* QspiIo2 */
|
||||
{0x0000309C, 0x72FF, 0x01}, /* QspiIo3 */
|
||||
{0x000030A4, 0x19FF, 0x02}, /* Dmic1Clk */
|
||||
{0x000030A8, 0x19FF, 0x02}, /* Dmic1Dat */
|
||||
{0x000030AC, 0x19FF, 0x02}, /* Dmic2Clk */
|
||||
{0x000030B0, 0x19FF, 0x02}, /* Dmic2Dat */
|
||||
{0x000030B4, 0x19FF, 0x02}, /* Dmic3Clk */
|
||||
{0x000030B8, 0x19FF, 0x02}, /* Dmic3Dat */
|
||||
{0x000030BC, 0x1DFF, 0x01}, /* Gen1I2cScl */
|
||||
{0x000030C0, 0x1DFF, 0x01}, /* Gen1I2cSda */
|
||||
{0x000030C4, 0x1DFF, 0x01}, /* Gen2I2cScl */
|
||||
{0x000030C8, 0x1DFF, 0x01}, /* Gen2I2cSda */
|
||||
{0x000030CC, 0x1DFF, 0x01}, /* Gen3I2cScl */
|
||||
{0x000030D0, 0x1DFF, 0x01}, /* Gen3I2cSda */
|
||||
{0x000030D4, 0x1DFF, 0x02}, /* CamI2cScl */
|
||||
{0x000030D8, 0x1DFF, 0x02}, /* CamI2cSda */
|
||||
{0x000030DC, 0x1DFF, 0x01}, /* PwrI2cScl */
|
||||
{0x000030E0, 0x1DFF, 0x01}, /* PwrI2cSda */
|
||||
{0x000030E4, 0x19FF, 0x01}, /* Uart1Tx */
|
||||
{0x000030E8, 0x19FF, 0x01}, /* Uart1Rx */
|
||||
{0x000030EC, 0x19FF, 0x01}, /* Uart1Rts */
|
||||
{0x000030F0, 0x19FF, 0x01}, /* Uart1Cts */
|
||||
{0x000030F4, 0x19FF, 0x00}, /* Uart2Tx */
|
||||
{0x000030F8, 0x19FF, 0x00}, /* Uart2Rx */
|
||||
{0x000030FC, 0x19FF, 0x02}, /* Uart2Rts */
|
||||
{0x00003100, 0x19FF, 0x02}, /* Uart2Cts */
|
||||
{0x00003104, 0x19FF, 0x02}, /* Uart3Tx */
|
||||
{0x00003108, 0x19FF, 0x02}, /* Uart3Rx */
|
||||
{0x0000310C, 0x19FF, 0x02}, /* Uart3Rts */
|
||||
{0x00003110, 0x19FF, 0x02}, /* Uart3Cts */
|
||||
{0x00003114, 0x19FF, 0x02}, /* Uart4Tx */
|
||||
{0x00003118, 0x19FF, 0x02}, /* Uart4Rx */
|
||||
{0x0000311C, 0x19FF, 0x02}, /* Uart4Rts */
|
||||
{0x00003120, 0x19FF, 0x02}, /* Uart4Cts */
|
||||
{0x00003124, 0x72FF, 0x01}, /* Dap1Fs */
|
||||
{0x00003128, 0x72FF, 0x01}, /* Dap1Din */
|
||||
{0x0000312C, 0x72FF, 0x01}, /* Dap1Dout */
|
||||
{0x00003130, 0x72FF, 0x01}, /* Dap1Sclk */
|
||||
{0x00003134, 0x72FF, 0x01}, /* Dap2Fs */
|
||||
{0x00003138, 0x72FF, 0x01}, /* Dap2Din */
|
||||
{0x0000313C, 0x72FF, 0x01}, /* Dap2Dout */
|
||||
{0x00003140, 0x72FF, 0x01}, /* Dap2Sclk */
|
||||
{0x00003144, 0x72FF, 0x01}, /* Dap4Fs */
|
||||
{0x00003148, 0x72FF, 0x01}, /* Dap4Din */
|
||||
{0x0000314C, 0x72FF, 0x01}, /* Dap4Dout */
|
||||
{0x00003150, 0x72FF, 0x01}, /* Dap4Sclk */
|
||||
{0x00003154, 0x72FF, 0x01}, /* Cam1Mclk */
|
||||
{0x00003158, 0x72FF, 0x01}, /* Cam2Mclk */
|
||||
{0x0000315C, 0x72FF, 0x01}, /* JtagRtck */
|
||||
{0x00003160, 0x118C, 0xFF}, /* Clk32kIn */
|
||||
{0x00003164, 0x72FF, 0x02}, /* Clk32kOut */
|
||||
{0x00003168, 0x1DFF, 0x01}, /* BattBcl */
|
||||
{0x0000316C, 0x11CC, 0xFF}, /* ClkReq */
|
||||
{0x00003170, 0x11CC, 0xFF}, /* CpuPwrReq */
|
||||
{0x00003174, 0x11CC, 0xFF}, /* PwrIntN */
|
||||
{0x00003178, 0x11CC, 0xFF}, /* Shutdown */
|
||||
{0x0000317C, 0x11CC, 0xFF}, /* CorePwrReq */
|
||||
{0x00003180, 0x19FF, 0x01}, /* AudMclk */
|
||||
{0x00003184, 0x19FF, 0x00}, /* DvfsPwm */
|
||||
{0x00003188, 0x19FF, 0x00}, /* DvfsClk */
|
||||
{0x0000318C, 0x19FF, 0x00}, /* GpioX1Aud */
|
||||
{0x00003190, 0x19FF, 0x00}, /* GpioX3Aud */
|
||||
{0x00003194, 0x1DFF, 0x00}, /* GpioPcc7 */
|
||||
{0x00003198, 0x1DFF, 0x01}, /* HdmiCec */
|
||||
{0x0000319C, 0x1DFF, 0x01}, /* HdmiIntDpHpd */
|
||||
{0x000031A0, 0x19FF, 0x01}, /* SpdifOut */
|
||||
{0x000031A4, 0x19FF, 0x01}, /* SpdifIn */
|
||||
{0x000031A8, 0x1DFF, 0x01}, /* UsbVbusEn0 */
|
||||
{0x000031AC, 0x1DFF, 0x01}, /* UsbVbusEn1 */
|
||||
{0x000031B0, 0x19FF, 0x01}, /* DpHpd0 */
|
||||
{0x000031B4, 0x19FF, 0x00}, /* WifiEn */
|
||||
{0x000031B8, 0x19FF, 0x00}, /* WifiRst */
|
||||
{0x000031BC, 0x19FF, 0x00}, /* WifiWakeAp */
|
||||
{0x000031C0, 0x19FF, 0x00}, /* ApWakeBt */
|
||||
{0x000031C4, 0x19FF, 0x00}, /* BtRst */
|
||||
{0x000031C8, 0x19FF, 0x00}, /* BtWakeAp */
|
||||
{0x000031CC, 0x19FF, 0x00}, /* ApWakeNfc */
|
||||
{0x000031D0, 0x19FF, 0x00}, /* NfcEn */
|
||||
{0x000031D4, 0x19FF, 0x00}, /* NfcInt */
|
||||
{0x000031D8, 0x19FF, 0x00}, /* GpsEn */
|
||||
{0x000031DC, 0x19FF, 0x00}, /* GpsRst */
|
||||
{0x000031E0, 0x19FF, 0x01}, /* CamRst */
|
||||
{0x000031E4, 0x19FF, 0x02}, /* CamAfEn */
|
||||
{0x000031E8, 0x19FF, 0x02}, /* CamFlashEn */
|
||||
{0x000031EC, 0x19FF, 0x01}, /* Cam1Pwdn */
|
||||
{0x000031F0, 0x19FF, 0x01}, /* Cam2Pwdn */
|
||||
{0x000031F4, 0x19FF, 0x01}, /* Cam1Strobe */
|
||||
{0x000031F8, 0x19FF, 0x01}, /* LcdTe */
|
||||
{0x000031FC, 0x19FF, 0x03}, /* LcdBlPwm */
|
||||
{0x00003200, 0x19FF, 0x00}, /* LcdBlEn */
|
||||
{0x00003204, 0x19FF, 0x00}, /* LcdRst */
|
||||
{0x00003208, 0x19FF, 0x01}, /* LcdGpio1 */
|
||||
{0x0000320C, 0x19FF, 0x02}, /* LcdGpio2 */
|
||||
{0x00003210, 0x19FF, 0x00}, /* ApReady */
|
||||
{0x00003214, 0x19FF, 0x00}, /* TouchRst */
|
||||
{0x00003218, 0x19FF, 0x01}, /* TouchClk */
|
||||
{0x0000321C, 0x19FF, 0x00}, /* ModemWakeAp */
|
||||
{0x00003220, 0x19FF, 0x00}, /* TouchInt */
|
||||
{0x00003224, 0x19FF, 0x00}, /* MotionInt */
|
||||
{0x00003228, 0x19FF, 0x00}, /* AlsProxInt */
|
||||
{0x0000322C, 0x19FF, 0x00}, /* TempAlert */
|
||||
{0x00003230, 0x19FF, 0x00}, /* ButtonPowerOn */
|
||||
{0x00003234, 0x19FF, 0x00}, /* ButtonVolUp */
|
||||
{0x00003238, 0x19FF, 0x00}, /* ButtonVolDown */
|
||||
{0x0000323C, 0x19FF, 0x00}, /* ButtonSlideSw */
|
||||
{0x00003240, 0x19FF, 0x00}, /* ButtonHome */
|
||||
{0x00003244, 0x19FF, 0x01}, /* GpioPa6 */
|
||||
{0x00003248, 0x19FF, 0x00}, /* GpioPe6 */
|
||||
{0x0000324C, 0x19FF, 0x00}, /* GpioPe7 */
|
||||
{0x00003250, 0x19FF, 0x00}, /* GpioPh6 */
|
||||
{0x00003254, 0x72FF, 0x02}, /* GpioPk0 */
|
||||
{0x00003258, 0x72FF, 0x02}, /* GpioPk1 */
|
||||
{0x0000325C, 0x72FF, 0x02}, /* GpioPk2 */
|
||||
{0x00003260, 0x72FF, 0x02}, /* GpioPk3 */
|
||||
{0x00003264, 0x72FF, 0x01}, /* GpioPk4 */
|
||||
{0x00003268, 0x72FF, 0x01}, /* GpioPk5 */
|
||||
{0x0000326C, 0x72FF, 0x01}, /* GpioPk6 */
|
||||
{0x00003270, 0x72FF, 0x01}, /* GpioPk7 */
|
||||
{0x00003274, 0x72FF, 0x00}, /* GpioPl0 */
|
||||
{0x00003278, 0x72FF, 0x01}, /* GpioPl1 */
|
||||
{0x0000327C, 0x72FF, 0x01}, /* GpioPz0 */
|
||||
{0x00003280, 0x72FF, 0x02}, /* GpioPz1 */
|
||||
{0x00003284, 0x72FF, 0x02}, /* GpioPz2 */
|
||||
{0x00003288, 0x72FF, 0x01}, /* GpioPz3 */
|
||||
{0x0000328C, 0x72FF, 0x01}, /* GpioPz4 */
|
||||
{0x00003290, 0x72FF, 0x01}, /* GpioPz5 */
|
||||
|
||||
/* 5.0.0+ only */
|
||||
{0x00003294, 0x1F2FF, 0x02}, /* Sdmmc2Dat0 */
|
||||
{0x00003298, 0x1F2FF, 0x02}, /* Sdmmc2Dat1 */
|
||||
{0x0000329C, 0x1F2FF, 0x02}, /* Sdmmc2Dat2 */
|
||||
{0x000032A0, 0x1F2FF, 0x02}, /* Sdmmc2Dat3 */
|
||||
{0x000032A4, 0x1F2FF, 0x02}, /* Sdmmc2Dat4 */
|
||||
{0x000032A8, 0x1F2FF, 0x02}, /* Sdmmc2Dat5 */
|
||||
{0x000032AC, 0x1F2FF, 0x02}, /* Sdmmc2Dat6 */
|
||||
{0x000032B0, 0x1F2FF, 0x02}, /* Sdmmc2Dat7 */
|
||||
{0x000032B4, 0x1F2FF, 0x02}, /* Sdmmc2Clk */
|
||||
{0x000032B8, 0x1F2FF, 0x00}, /* Sdmmc2Clkb */
|
||||
{0x000032BC, 0x1F2FF, 0x02}, /* Sdmmc2Cmd */
|
||||
{0x000032C0, 0x1F2FF, 0x00}, /* Sdmmc2Dqs */
|
||||
{0x000032C4, 0x1F2FF, 0x00}, /* Sdmmc2Dqsb */
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxPadNameMax = (sizeof(PinmuxMap) / sizeof(PinmuxMap[0]));
|
||||
|
||||
static constexpr PinmuxDrivePadDefinition PinmuxDrivePadMap[] = {
|
||||
{0x000008E4, 0x01F1F000}, /* AlsProxInt */
|
||||
{0x000008E8, 0x01F1F000}, /* ApReady */
|
||||
{0x000008EC, 0x01F1F000}, /* ApWakeBt */
|
||||
{0x000008F0, 0x01F1F000}, /* ApWakeNfc */
|
||||
{0x000008F4, 0x01F1F000}, /* AudMclk */
|
||||
{0x000008F8, 0x01F1F000}, /* BattBcl */
|
||||
{0x000008FC, 0x01F1F000}, /* BtRst */
|
||||
{0x00000900, 0x01F1F000}, /* BtWakeAp */
|
||||
{0x00000904, 0x01F1F000}, /* ButtonHome */
|
||||
{0x00000908, 0x01F1F000}, /* ButtonPowerOn */
|
||||
{0x0000090C, 0x01F1F000}, /* ButtonSlideSw */
|
||||
{0x00000910, 0x01F1F000}, /* ButtonVolDown */
|
||||
{0x00000914, 0x01F1F000}, /* ButtonVolUp */
|
||||
{0x00000918, 0x01F1F000}, /* Cam1Mclk */
|
||||
{0x0000091C, 0x01F1F000}, /* Cam1Pwdn */
|
||||
{0x00000920, 0x01F1F000}, /* Cam1Strobe */
|
||||
{0x00000924, 0x01F1F000}, /* Cam2Mclk */
|
||||
{0x00000928, 0x01F1F000}, /* Cam2Pwdn */
|
||||
{0x0000092C, 0x01F1F000}, /* CamAfEn */
|
||||
{0x00000930, 0x01F1F000}, /* CamFlashEn */
|
||||
{0x00000934, 0x01F1F000}, /* CamI2cScl */
|
||||
{0x00000938, 0x01F1F000}, /* CamI2cSda */
|
||||
{0x0000093C, 0x01F1F000}, /* CamRst */
|
||||
{0x00000940, 0x01F1F000}, /* Clk32kIn */
|
||||
{0x00000944, 0x01F1F000}, /* Clk32kOut */
|
||||
{0x00000948, 0x01F1F000}, /* ClkReq */
|
||||
{0x0000094C, 0x01F1F000}, /* CorePwrReq */
|
||||
{0x00000950, 0x01F1F000}, /* CpuPwrReq */
|
||||
{0x00000954, 0xF0000000}, /* Dap1Din */
|
||||
{0x00000958, 0xF0000000}, /* Dap1Dout */
|
||||
{0x0000095C, 0xF0000000}, /* Dap1Fs */
|
||||
{0x00000960, 0xF0000000}, /* Dap1Sclk */
|
||||
{0x00000964, 0xF0000000}, /* Dap2Din */
|
||||
{0x00000968, 0xF0000000}, /* Dap2Dout */
|
||||
{0x0000096C, 0xF0000000}, /* Dap2Fs */
|
||||
{0x00000970, 0xF0000000}, /* Dap2Sclk */
|
||||
{0x00000974, 0x01F1F000}, /* Dap4Din */
|
||||
{0x00000978, 0x01F1F000}, /* Dap4Dout */
|
||||
{0x0000097C, 0x01F1F000}, /* Dap4Fs */
|
||||
{0x00000980, 0x01F1F000}, /* Dap4Sclk */
|
||||
{0x00000984, 0x01F1F000}, /* Dmic1Clk */
|
||||
{0x00000988, 0x01F1F000}, /* Dmic1Dat */
|
||||
{0x0000098C, 0x01F1F000}, /* Dmic2Clk */
|
||||
{0x00000990, 0x01F1F000}, /* Dmic2Dat */
|
||||
{0x00000994, 0x01F1F000}, /* Dmic3Clk */
|
||||
{0x00000998, 0x01F1F000}, /* Dmic3Dat */
|
||||
{0x0000099C, 0x01F1F000}, /* DpHpd */
|
||||
{0x000009A0, 0x01F1F000}, /* DvfsClk */
|
||||
{0x000009A4, 0x01F1F000}, /* DvfsPwm */
|
||||
{0x000009A8, 0x01F1F000}, /* Gen1I2cScl */
|
||||
{0x000009AC, 0x01F1F000}, /* Gen1I2cSda */
|
||||
{0x000009B0, 0x01F1F000}, /* Gen2I2cScl */
|
||||
{0x000009B4, 0x01F1F000}, /* Gen2I2cSda */
|
||||
{0x000009B8, 0x01F1F000}, /* Gen3I2cScl */
|
||||
{0x000009BC, 0x01F1F000}, /* Gen3I2cSda */
|
||||
{0x000009C0, 0x01F1F000}, /* GpioPa6 */
|
||||
{0x000009C4, 0x01F1F000}, /* GpioPcc7 */
|
||||
{0x000009C8, 0x01F1F000}, /* GpioPe6 */
|
||||
{0x000009CC, 0x01F1F000}, /* GpioPe7 */
|
||||
{0x000009D0, 0x01F1F000}, /* GpioPh6 */
|
||||
{0x000009D4, 0xF0000000}, /* GpioPk0 */
|
||||
{0x000009D8, 0xF0000000}, /* GpioPk1 */
|
||||
{0x000009DC, 0xF0000000}, /* GpioPk2 */
|
||||
{0x000009E0, 0xF0000000}, /* GpioPk3 */
|
||||
{0x000009E4, 0xF0000000}, /* GpioPk4 */
|
||||
{0x000009E8, 0xF0000000}, /* GpioPk5 */
|
||||
{0x000009EC, 0xF0000000}, /* GpioPk6 */
|
||||
{0x000009F0, 0xF0000000}, /* GpioPk7 */
|
||||
{0x000009F4, 0xF0000000}, /* GpioPl0 */
|
||||
{0x000009F8, 0xF0000000}, /* GpioPl1 */
|
||||
{0x000009FC, 0x07F7F000}, /* GpioPz0 */
|
||||
{0x00000A00, 0x07F7F000}, /* GpioPz1 */
|
||||
{0x00000A04, 0x07F7F000}, /* GpioPz2 */
|
||||
{0x00000A08, 0x07F7F000}, /* GpioPz3 */
|
||||
{0x00000A0C, 0x07F7F000}, /* GpioPz4 */
|
||||
{0x00000A10, 0x07F7F000}, /* GpioPz5 */
|
||||
{0x00000A14, 0x01F1F000}, /* GpioX1Aud */
|
||||
{0x00000A18, 0x01F1F000}, /* GpioX3Aud */
|
||||
{0x00000A1C, 0x01F1F000}, /* GpsEn */
|
||||
{0x00000A20, 0x01F1F000}, /* GpsRst */
|
||||
{0x00000A24, 0x01F1F000}, /* HdmiCec */
|
||||
{0x00000A28, 0x01F1F000}, /* HdmiIntDpHpd */
|
||||
{0x00000A2C, 0x01F1F000}, /* JtagRtck */
|
||||
{0x00000A30, 0x01F1F000}, /* LcdBlEn */
|
||||
{0x00000A34, 0x01F1F000}, /* LcdBlPwm */
|
||||
{0x00000A38, 0x01F1F000}, /* LcdGpio1 */
|
||||
{0x00000A3C, 0x01F1F000}, /* LcdGpio2 */
|
||||
{0x00000A40, 0x01F1F000}, /* LcdRst */
|
||||
{0x00000A44, 0x01F1F000}, /* LcdTe */
|
||||
{0x00000A48, 0x01F1F000}, /* ModemWakeAp */
|
||||
{0x00000A4C, 0x01F1F000}, /* MotionInt */
|
||||
{0x00000A50, 0x01F1F000}, /* NfcEn */
|
||||
{0x00000A54, 0x01F1F000}, /* NfcInt */
|
||||
{0x00000A58, 0x01F1F000}, /* PexL0ClkReqN */
|
||||
{0x00000A5C, 0x01F1F000}, /* PexL0RstN */
|
||||
{0x00000A60, 0x01F1F000}, /* PexL1ClkreqN */
|
||||
{0x00000A64, 0x01F1F000}, /* PexL1RstN */
|
||||
{0x00000A68, 0x01F1F000}, /* PexWakeN */
|
||||
{0x00000A6C, 0x01F1F000}, /* PwrI2cScl */
|
||||
{0x00000A70, 0x01F1F000}, /* PwrI2cSda */
|
||||
{0x00000A74, 0x01F1F000}, /* PwrIntN */
|
||||
{0x00000A78, 0x07F7F000}, /* QspiComp */
|
||||
{0x00000A90, 0xF0000000}, /* QspiSck */
|
||||
{0x00000A94, 0x01F1F000}, /* SataLedActive */
|
||||
{0x00000A98, 0xF7F7F000}, /* Sdmmc1Pad */
|
||||
{0x00000AB0, 0xF7F7F000}, /* Sdmmc3Pad */
|
||||
{0x00000AC8, 0x01F1F000}, /* Shutdown */
|
||||
{0x00000ACC, 0x01F1F000}, /* SpdifIn */
|
||||
{0x00000AD0, 0x01F1F000}, /* SpdifOut */
|
||||
{0x00000AD4, 0xF0000000}, /* Spi1Cs0 */
|
||||
{0x00000AD8, 0xF0000000}, /* Spi1Cs1 */
|
||||
{0x00000ADC, 0xF0000000}, /* Spi1Miso */
|
||||
{0x00000AE0, 0xF0000000}, /* Spi1Mosi */
|
||||
{0x00000AE4, 0xF0000000}, /* Spi1Sck */
|
||||
{0x00000AE8, 0xF0000000}, /* Spi2Cs0 */
|
||||
{0x00000AEC, 0xF0000000}, /* Spi2Cs1 */
|
||||
{0x00000AF0, 0xF0000000}, /* Spi2Miso */
|
||||
{0x00000AF4, 0xF0000000}, /* Spi2Mosi */
|
||||
{0x00000AF8, 0xF0000000}, /* Spi2Sck */
|
||||
{0x00000AFC, 0xF0000000}, /* Spi4Cs0 */
|
||||
{0x00000B00, 0xF0000000}, /* Spi4Miso */
|
||||
{0x00000B04, 0xF0000000}, /* Spi4Mosi */
|
||||
{0x00000B08, 0xF0000000}, /* Spi4Sck */
|
||||
{0x00000B0C, 0x01F1F000}, /* TempAlert */
|
||||
{0x00000B10, 0x01F1F000}, /* TouchClk */
|
||||
{0x00000B14, 0x01F1F000}, /* TouchInt */
|
||||
{0x00000B18, 0x01F1F000}, /* TouchRst */
|
||||
{0x00000B1C, 0x01F1F000}, /* Uart1Cts */
|
||||
{0x00000B20, 0x01F1F000}, /* Uart1Rts */
|
||||
{0x00000B24, 0x01F1F000}, /* Uart1Rx */
|
||||
{0x00000B28, 0x01F1F000}, /* Uart1Tx */
|
||||
{0x00000B2C, 0x01F1F000}, /* Uart2Cts */
|
||||
{0x00000B30, 0x01F1F000}, /* Uart2Rts */
|
||||
{0x00000B34, 0x01F1F000}, /* Uart2Rx */
|
||||
{0x00000B38, 0x01F1F000}, /* Uart2Tx */
|
||||
{0x00000B3C, 0x01F1F000}, /* Uart3Cts */
|
||||
{0x00000B40, 0x01F1F000}, /* Uart3Rts */
|
||||
{0x00000B44, 0x01F1F000}, /* Uart3Rx */
|
||||
{0x00000B48, 0x01F1F000}, /* Uart3Tx */
|
||||
{0x00000B4C, 0x01F1F000}, /* Uart4Cts */
|
||||
{0x00000B50, 0x01F1F000}, /* Uart4Rts */
|
||||
{0x00000B54, 0x01F1F000}, /* Uart4Rx */
|
||||
{0x00000B58, 0x01F1F000}, /* Uart4Tx */
|
||||
{0x00000B5C, 0x01F1F000}, /* UsbVbusEn0 */
|
||||
{0x00000B60, 0x01F1F000}, /* UsbVbusEn1 */
|
||||
{0x00000B64, 0x01F1F000}, /* WifiEn */
|
||||
{0x00000B68, 0x01F1F000}, /* WifiRst */
|
||||
{0x00000B6C, 0x01F1F000}, /* WifiWakeAp */
|
||||
};
|
||||
|
||||
static constexpr u32 PinmuxDrivePadNameMax = (sizeof(PinmuxDrivePadMap) / sizeof(PinmuxDrivePadMap[0]));
|
||||
487
stratosphere/boot/source/boot_pinmux_utils.cpp
Normal file
487
stratosphere/boot/source/boot_pinmux_utils.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boot_functions.hpp"
|
||||
#include "boot_pinmux_map.hpp"
|
||||
|
||||
static bool g_initialized_pinmux_vaddr = false;
|
||||
static uintptr_t g_pinmux_vaddr = 0;
|
||||
|
||||
static inline const PinmuxDefinition *GetPinmuxDefinition(u32 pinmux_name) {
|
||||
if (pinmux_name >= PinmuxPadNameMax) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return &PinmuxMap[pinmux_name];
|
||||
}
|
||||
|
||||
static inline const PinmuxDrivePadDefinition *GetPinmuxDrivePadDefinition(u32 pinmux_name) {
|
||||
if (pinmux_name >= PinmuxDrivePadNameMax) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return &PinmuxDrivePadMap[pinmux_name];
|
||||
}
|
||||
|
||||
static uintptr_t GetPinmuxBaseAddress() {
|
||||
if (!g_initialized_pinmux_vaddr) {
|
||||
u64 vaddr;
|
||||
if (R_FAILED(svcQueryIoMapping(&vaddr, Boot::ApbMiscPhysicalBase, 0x4000))) {
|
||||
std::abort();
|
||||
}
|
||||
g_pinmux_vaddr = vaddr;
|
||||
g_initialized_pinmux_vaddr = true;
|
||||
}
|
||||
return g_pinmux_vaddr;
|
||||
}
|
||||
|
||||
u32 Boot::PinmuxUpdatePark(u32 pinmux_name) {
|
||||
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
|
||||
const PinmuxDefinition *pinmux_def = GetPinmuxDefinition(pinmux_name);
|
||||
|
||||
/* Fetch this PINMUX's register offset */
|
||||
u32 pinmux_reg_offset = pinmux_def->reg_offset;
|
||||
|
||||
/* Fetch this PINMUX's mask value */
|
||||
u32 pinmux_mask_val = pinmux_def->mask_val;
|
||||
|
||||
/* Get current register ptr. */
|
||||
volatile u32 *pinmux_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_reg_offset);
|
||||
|
||||
/* Read from the PINMUX register */
|
||||
u32 pinmux_val = *pinmux_reg;
|
||||
|
||||
/* This PINMUX supports park change */
|
||||
if (pinmux_mask_val & 0x20) {
|
||||
/* Clear park status if set */
|
||||
if (pinmux_val & 0x20) {
|
||||
pinmux_val &= ~(0x20);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write to the appropriate PINMUX register */
|
||||
*pinmux_reg = pinmux_val;
|
||||
|
||||
/* Do a dummy read from the PINMUX register */
|
||||
pinmux_val = *pinmux_reg;
|
||||
|
||||
return pinmux_val;
|
||||
}
|
||||
|
||||
u32 Boot::PinmuxUpdatePad(u32 pinmux_name, u32 pinmux_config_val, u32 pinmux_config_mask_val) {
|
||||
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
|
||||
const PinmuxDefinition *pinmux_def = GetPinmuxDefinition(pinmux_name);
|
||||
|
||||
/* Fetch this PINMUX's register offset */
|
||||
u32 pinmux_reg_offset = pinmux_def->reg_offset;
|
||||
|
||||
/* Fetch this PINMUX's mask value */
|
||||
u32 pinmux_mask_val = pinmux_def->mask_val;
|
||||
|
||||
/* Get current register ptr. */
|
||||
volatile u32 *pinmux_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_reg_offset);
|
||||
|
||||
/* Read from the PINMUX register */
|
||||
u32 pinmux_val = *pinmux_reg;
|
||||
|
||||
/* This PINMUX register is locked */
|
||||
if (pinmux_val & 0x80)
|
||||
return pinmux_val;
|
||||
|
||||
u32 pm_config_val = (pinmux_config_val & 0x07);
|
||||
u32 pm_val = pm_config_val;
|
||||
|
||||
/* Adjust PM */
|
||||
if (pinmux_config_mask_val & 0x07) {
|
||||
/* Default to safe value */
|
||||
if (pm_config_val >= 0x06)
|
||||
pm_val = 0x04;
|
||||
|
||||
/* Apply additional changes first */
|
||||
if (pm_config_val == 0x05) {
|
||||
/* This pin supports PUPD change */
|
||||
if (pinmux_mask_val & 0x0C) {
|
||||
/* Change PUPD */
|
||||
if ((pinmux_val & 0x0C) != 0x04) {
|
||||
pinmux_val &= 0xFFFFFFF3;
|
||||
pinmux_val |= 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports Tristate change */
|
||||
if (pinmux_mask_val & 0x10) {
|
||||
/* Change Tristate */
|
||||
if (!(pinmux_val & 0x10)) {
|
||||
pinmux_val |= 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EInput change */
|
||||
if (pinmux_mask_val & 0x40) {
|
||||
/* Change EInput */
|
||||
if (pinmux_val & 0x40) {
|
||||
pinmux_val &= 0xFFFFFFBF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default to safe value */
|
||||
pm_val = 0x04;
|
||||
}
|
||||
|
||||
/* Translate PM value if necessary */
|
||||
if ((pm_val & 0xFF) == 0x04)
|
||||
pm_val = pinmux_def->pm_val;
|
||||
|
||||
/* This pin supports PM change */
|
||||
if (pinmux_mask_val & 0x03) {
|
||||
/* Change PM */
|
||||
if ((pinmux_val & 0x03) != (pm_val & 0x03)) {
|
||||
pinmux_val &= 0xFFFFFFFC;
|
||||
pinmux_val |= (pm_val & 0x03);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 pupd_config_val = (pinmux_config_val & 0x18);
|
||||
|
||||
/* Adjust PUPD */
|
||||
if (pinmux_config_mask_val & 0x18) {
|
||||
if (pupd_config_val < 0x11) {
|
||||
/* This pin supports PUPD change */
|
||||
if (pinmux_mask_val & 0x0C) {
|
||||
/* Change PUPD */
|
||||
if ((pinmux_val & 0x0C) != (pupd_config_val >> 0x03)) {
|
||||
pinmux_val &= 0xFFFFFFF3;
|
||||
pinmux_val |= (pupd_config_val >> 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 eod_config_val = (pinmux_config_val & 0x60);
|
||||
|
||||
/* Adjust EOd field */
|
||||
if (pinmux_config_mask_val & 0x60) {
|
||||
if (eod_config_val == 0x20) {
|
||||
/* This pin supports Tristate change */
|
||||
if (pinmux_mask_val & 0x10) {
|
||||
/* Change Tristate */
|
||||
if (!(pinmux_val & 0x10)) {
|
||||
pinmux_val |= 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EInput change */
|
||||
if (pinmux_mask_val & 0x40) {
|
||||
/* Change EInput */
|
||||
if (!(pinmux_val & 0x40)) {
|
||||
pinmux_val |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EOd change */
|
||||
if (pinmux_mask_val & 0x800) {
|
||||
/* Change EOd */
|
||||
if (pinmux_val & 0x800) {
|
||||
pinmux_val &= 0xFFFFF7FF;
|
||||
}
|
||||
}
|
||||
} else if (eod_config_val == 0x40) {
|
||||
/* This pin supports Tristate change */
|
||||
if (pinmux_mask_val & 0x10) {
|
||||
/* Change Tristate */
|
||||
if (pinmux_val & 0x10) {
|
||||
pinmux_val &= 0xFFFFFFEF;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EInput change */
|
||||
if (pinmux_mask_val & 0x40) {
|
||||
/* Change EInput */
|
||||
if (!(pinmux_val & 0x40)) {
|
||||
pinmux_val |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EOd change */
|
||||
if (pinmux_mask_val & 0x800) {
|
||||
/* Change EOd */
|
||||
if (pinmux_val & 0x800) {
|
||||
pinmux_val &= 0xFFFFF7FF;
|
||||
}
|
||||
}
|
||||
} else if (eod_config_val == 0x60) {
|
||||
/* This pin supports Tristate change */
|
||||
if (pinmux_mask_val & 0x10) {
|
||||
/* Change Tristate */
|
||||
if (pinmux_val & 0x10) {
|
||||
pinmux_val &= 0xFFFFFFEF;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EInput change */
|
||||
if (pinmux_mask_val & 0x40) {
|
||||
/* Change EInput */
|
||||
if (!(pinmux_val & 0x40)) {
|
||||
pinmux_val |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EOd change */
|
||||
if (pinmux_mask_val & 0x800) {
|
||||
/* Change EOd */
|
||||
if (!(pinmux_val & 0x800)) {
|
||||
pinmux_val |= 0x800;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* This pin supports Tristate change */
|
||||
if (pinmux_mask_val & 0x10) {
|
||||
/* Change Tristate */
|
||||
if (pinmux_val & 0x10) {
|
||||
pinmux_val &= 0xFFFFFFEF;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EInput change */
|
||||
if (pinmux_mask_val & 0x40) {
|
||||
/* Change EInput */
|
||||
if (pinmux_val & 0x40) {
|
||||
pinmux_val &= 0xFFFFFFBF;
|
||||
}
|
||||
}
|
||||
|
||||
/* This pin supports EOd change */
|
||||
if (pinmux_mask_val & 0x800) {
|
||||
/* Change EOd */
|
||||
if (pinmux_val & 0x800) {
|
||||
pinmux_val &= 0xFFFFF7FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 lock_config_val = (pinmux_config_val & 0x80);
|
||||
|
||||
/* Adjust Lock */
|
||||
if (pinmux_config_mask_val & 0x80) {
|
||||
/* This pin supports Lock change */
|
||||
if (pinmux_mask_val & 0x80) {
|
||||
/* Change Lock */
|
||||
if ((pinmux_val ^ pinmux_config_val) & 0x80) {
|
||||
pinmux_val &= 0xFFFFFF7F;
|
||||
pinmux_val |= lock_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 ioreset_config_val = ((pinmux_config_val >> 0x08) & 0x10000);
|
||||
|
||||
/* Adjust IoReset */
|
||||
if (pinmux_config_mask_val & 0x100) {
|
||||
/* This pin supports IoReset change */
|
||||
if (pinmux_mask_val & 0x10000) {
|
||||
/* Change IoReset */
|
||||
if (((pinmux_val >> 0x10) ^ (pinmux_config_val >> 0x08)) & 0x01) {
|
||||
pinmux_val |= ioreset_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 park_config_val = ((pinmux_config_val >> 0x0A) & 0x20);
|
||||
|
||||
/* Adjust Park */
|
||||
if (pinmux_config_mask_val & 0x400) {
|
||||
/* This pin supports Park change */
|
||||
if (pinmux_mask_val & 0x20) {
|
||||
/* Change Park */
|
||||
if (((pinmux_val >> 0x05) ^ (pinmux_config_val >> 0x0A)) & 0x01) {
|
||||
pinmux_val |= park_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 elpdr_config_val = ((pinmux_config_val >> 0x0B) & 0x100);
|
||||
|
||||
/* Adjust ELpdr */
|
||||
if (pinmux_config_mask_val & 0x800) {
|
||||
/* This pin supports ELpdr change */
|
||||
if (pinmux_mask_val & 0x100) {
|
||||
/* Change ELpdr */
|
||||
if (((pinmux_val >> 0x08) ^ (pinmux_config_val >> 0x0B)) & 0x01) {
|
||||
pinmux_val |= elpdr_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 ehsm_config_val = ((pinmux_config_val >> 0x0C) & 0x200);
|
||||
|
||||
/* Adjust EHsm */
|
||||
if (pinmux_config_mask_val & 0x1000) {
|
||||
/* This pin supports EHsm change */
|
||||
if (pinmux_mask_val & 0x200) {
|
||||
/* Change EHsm */
|
||||
if (((pinmux_val >> 0x09) ^ (pinmux_config_val >> 0x0C)) & 0x01) {
|
||||
pinmux_val |= ehsm_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 eiohv_config_val = ((pinmux_config_val >> 0x09) & 0x400);
|
||||
|
||||
/* Adjust EIoHv */
|
||||
if (pinmux_config_mask_val & 0x200) {
|
||||
/* This pin supports EIoHv change */
|
||||
if (pinmux_mask_val & 0x400) {
|
||||
/* Change EIoHv */
|
||||
if (((pinmux_val >> 0x0A) ^ (pinmux_config_val >> 0x09)) & 0x01) {
|
||||
pinmux_val |= eiohv_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 eschmt_config_val = ((pinmux_config_val >> 0x0D) & 0x1000);
|
||||
|
||||
/* Adjust ESchmt */
|
||||
if (pinmux_config_mask_val & 0x2000) {
|
||||
/* This pin supports ESchmt change */
|
||||
if (pinmux_mask_val & 0x1000) {
|
||||
/* Change ESchmt */
|
||||
if (((pinmux_val >> 0x0C) ^ (pinmux_config_val >> 0x0D)) & 0x01) {
|
||||
pinmux_val |= eschmt_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 preemp_config_val = ((pinmux_config_val >> 0x0D) & 0x8000);
|
||||
|
||||
/* Adjust Preemp */
|
||||
if (pinmux_config_mask_val & 0x10000) {
|
||||
/* This pin supports Preemp change */
|
||||
if (pinmux_mask_val & 0x8000) {
|
||||
/* Change Preemp */
|
||||
if (((pinmux_val >> 0x0F) ^ (pinmux_config_val >> 0x10)) & 0x01) {
|
||||
pinmux_val |= preemp_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 drvtype_config_val = ((pinmux_config_val >> 0x0E) & 0x6000);
|
||||
|
||||
/* Adjust DrvType */
|
||||
if (pinmux_config_mask_val & 0xC000) {
|
||||
/* This pin supports DrvType change */
|
||||
if (pinmux_mask_val & 0x6000) {
|
||||
/* Change DrvType */
|
||||
if (((pinmux_val >> 0x0D) ^ (pinmux_config_val >> 0x0E)) & 0x03) {
|
||||
pinmux_val |= drvtype_config_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write to the appropriate PINMUX register */
|
||||
*pinmux_reg = pinmux_val;
|
||||
|
||||
/* Do a dummy read from the PINMUX register */
|
||||
pinmux_val = *pinmux_reg;
|
||||
|
||||
return pinmux_val;
|
||||
}
|
||||
|
||||
u32 Boot::PinmuxUpdateDrivePad(u32 pinmux_drivepad_name, u32 pinmux_drivepad_config_val, u32 pinmux_drivepad_config_mask_val) {
|
||||
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
|
||||
const PinmuxDrivePadDefinition *pinmux_drivepad_def = GetPinmuxDrivePadDefinition(pinmux_drivepad_name);
|
||||
|
||||
/* Fetch this PINMUX drive group's register offset */
|
||||
u32 pinmux_drivepad_reg_offset = pinmux_drivepad_def->reg_offset;
|
||||
|
||||
/* Fetch this PINMUX drive group's mask value */
|
||||
u32 pinmux_drivepad_mask_val = pinmux_drivepad_def->mask_val;
|
||||
|
||||
/* Get current register ptr. */
|
||||
volatile u32 *pinmux_drivepad_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_drivepad_reg_offset);
|
||||
|
||||
/* Read from the PINMUX drive group register */
|
||||
u32 pinmux_drivepad_val = *pinmux_drivepad_reg;
|
||||
|
||||
/* Adjust DriveDownStrength */
|
||||
if (pinmux_drivepad_config_mask_val & 0x1F000) {
|
||||
u32 mask_val = 0x7F000;
|
||||
|
||||
/* Adjust mask value */
|
||||
if ((pinmux_drivepad_mask_val & 0x7F000) != 0x7F000)
|
||||
mask_val = 0x1F000;
|
||||
|
||||
/* This drive group supports DriveDownStrength change */
|
||||
if (pinmux_drivepad_mask_val & mask_val) {
|
||||
/* Change DriveDownStrength */
|
||||
if (((pinmux_drivepad_config_val & 0x7F000) & mask_val) != (pinmux_drivepad_val & mask_val)) {
|
||||
pinmux_drivepad_val &= ~(mask_val);
|
||||
pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F000) & mask_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust DriveUpStrength */
|
||||
if (pinmux_drivepad_config_mask_val & 0x1F00000) {
|
||||
u32 mask_val = 0x7F00000;
|
||||
|
||||
/* Adjust mask value */
|
||||
if ((pinmux_drivepad_mask_val & 0x7F00000) != 0x7F00000)
|
||||
mask_val = 0x1F00000;
|
||||
|
||||
/* This drive group supports DriveUpStrength change */
|
||||
if (pinmux_drivepad_mask_val & mask_val) {
|
||||
/* Change DriveUpStrength */
|
||||
if (((pinmux_drivepad_config_val & 0x7F00000) & mask_val) != (pinmux_drivepad_val & mask_val)) {
|
||||
pinmux_drivepad_val &= ~(mask_val);
|
||||
pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F00000) & mask_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust DriveDownSlew */
|
||||
if (pinmux_drivepad_config_mask_val & 0x30000000) {
|
||||
/* This drive group supports DriveDownSlew change */
|
||||
if (pinmux_drivepad_mask_val & 0x30000000) {
|
||||
/* Change DriveDownSlew */
|
||||
if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0x30000000) {
|
||||
pinmux_drivepad_val &= 0xCFFFFFFF;
|
||||
pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0x30000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust DriveUpSlew */
|
||||
if (pinmux_drivepad_config_mask_val & 0xC0000000) {
|
||||
/* This drive group supports DriveUpSlew change */
|
||||
if (pinmux_drivepad_mask_val & 0xC0000000) {
|
||||
/* Change DriveUpSlew */
|
||||
if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0xC0000000) {
|
||||
pinmux_drivepad_val &= 0x3FFFFFFF;
|
||||
pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0xC0000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write to the appropriate PINMUX drive group register */
|
||||
*pinmux_drivepad_reg = pinmux_drivepad_val;
|
||||
|
||||
/* Do a dummy read from the PINMUX drive group register */
|
||||
pinmux_drivepad_val = *pinmux_drivepad_reg;
|
||||
|
||||
return pinmux_drivepad_val;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user