mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-11 23:34:50 +00:00
boot: Implement DetectBootReason
This commit is contained in:
parent
fe0d41623c
commit
93fb060fac
9 changed files with 317 additions and 2 deletions
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. */
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ class Boot {
|
||||||
static void ChangeGpioVoltageTo1_8v();
|
static void ChangeGpioVoltageTo1_8v();
|
||||||
static void SetInitialGpioConfiguration();
|
static void SetInitialGpioConfiguration();
|
||||||
static void CheckClock();
|
static void CheckClock();
|
||||||
|
static void DetectBootReason();
|
||||||
|
|
||||||
/* Power utilities. */
|
/* Power utilities. */
|
||||||
static void RebootSystem();
|
static void RebootSystem();
|
||||||
|
@ -45,6 +46,8 @@ class Boot {
|
||||||
|
|
||||||
/* SPL Utilities. */
|
/* SPL Utilities. */
|
||||||
static HardwareType GetHardwareType();
|
static HardwareType GetHardwareType();
|
||||||
|
static u32 GetBootReason();
|
||||||
|
static bool IsRecoveryBoot();
|
||||||
|
|
||||||
/* I2C Utilities. */
|
/* I2C Utilities. */
|
||||||
static Result ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
static Result ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
||||||
|
|
|
@ -119,7 +119,8 @@ int main(int argc, char **argv)
|
||||||
/* Check USB PLL/UTMIP clock. */
|
/* Check USB PLL/UTMIP clock. */
|
||||||
Boot::CheckClock();
|
Boot::CheckClock();
|
||||||
|
|
||||||
/* TODO: DetectBootReason(); */
|
/* Talk to PMIC/RTC, set boot reason with SPL. */
|
||||||
|
Boot::DetectBootReason();
|
||||||
|
|
||||||
/* TODO: ShowSplashScreen(); */
|
/* TODO: ShowSplashScreen(); */
|
||||||
|
|
||||||
|
|
63
stratosphere/boot/source/boot_pmic_driver.cpp
Normal file
63
stratosphere/boot/source/boot_pmic_driver.cpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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_pmic_driver.hpp"
|
||||||
|
|
||||||
|
void PmicDriver::ShutdownSystem() {
|
||||||
|
if (R_FAILED(this->ShutdownSystem(false))) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PmicDriver::RebootSystem() {
|
||||||
|
if (R_FAILED(this->ShutdownSystem(true))) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmicDriver::GetAcOk(bool *out) {
|
||||||
|
u8 power_status;
|
||||||
|
Result rc = this->GetPowerStatus(&power_status);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = (power_status & 0x02) != 0;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmicDriver::GetPowerIntr(u8 *out) {
|
||||||
|
const u8 addr = 0x0B;
|
||||||
|
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmicDriver::GetPowerStatus(u8 *out) {
|
||||||
|
const u8 addr = 0x15;
|
||||||
|
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmicDriver::GetNvErc(u8 *out) {
|
||||||
|
const u8 addr = 0x0C;
|
||||||
|
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmicDriver::ShutdownSystem(bool reboot) {
|
||||||
|
/* TODO: Implement this. */
|
||||||
|
std::abort();
|
||||||
|
}
|
45
stratosphere/boot/source/boot_pmic_driver.hpp
Normal file
45
stratosphere/boot/source/boot_pmic_driver.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
class PmicDriver {
|
||||||
|
private:
|
||||||
|
I2cSessionImpl i2c_session;
|
||||||
|
public:
|
||||||
|
PmicDriver() {
|
||||||
|
I2cDriver::Initialize();
|
||||||
|
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max77620Pmic);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PmicDriver() {
|
||||||
|
I2cDriver::CloseSession(this->i2c_session);
|
||||||
|
I2cDriver::Finalize();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Result GetPowerStatus(u8 *out);
|
||||||
|
Result ShutdownSystem(bool reboot);
|
||||||
|
public:
|
||||||
|
void ShutdownSystem();
|
||||||
|
void RebootSystem();
|
||||||
|
Result GetAcOk(bool *out);
|
||||||
|
Result GetPowerIntr(u8 *out);
|
||||||
|
Result GetNvErc(u8 *out);
|
||||||
|
};
|
41
stratosphere/boot/source/boot_rtc_driver.cpp
Normal file
41
stratosphere/boot/source/boot_rtc_driver.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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_rtc_driver.hpp"
|
||||||
|
|
||||||
|
Result RtcDriver::ReadRtcRegister(u8 *out, u8 address) {
|
||||||
|
const u8 update_addr = 0x04;
|
||||||
|
const u8 update_val = 0x10;
|
||||||
|
Result rc = Boot::WriteI2cRegister(this->i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr));
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
svcSleepThread(16'000'000ul);
|
||||||
|
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &address, sizeof(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RtcDriver::GetRtcIntr(u8 *out) {
|
||||||
|
const u8 addr = 0x00;
|
||||||
|
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RtcDriver::GetRtcIntrM(u8 *out) {
|
||||||
|
const u8 addr = 0x01;
|
||||||
|
return this->ReadRtcRegister(out, addr);
|
||||||
|
}
|
41
stratosphere/boot/source/boot_rtc_driver.hpp
Normal file
41
stratosphere/boot/source/boot_rtc_driver.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
class RtcDriver {
|
||||||
|
private:
|
||||||
|
I2cSessionImpl i2c_session;
|
||||||
|
public:
|
||||||
|
RtcDriver() {
|
||||||
|
I2cDriver::Initialize();
|
||||||
|
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max77620Rtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
~RtcDriver() {
|
||||||
|
I2cDriver::CloseSession(this->i2c_session);
|
||||||
|
I2cDriver::Finalize();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Result ReadRtcRegister(u8 *out, u8 address);
|
||||||
|
public:
|
||||||
|
Result GetRtcIntr(u8 *out);
|
||||||
|
Result GetRtcIntrM(u8 *out);
|
||||||
|
};
|
|
@ -23,3 +23,11 @@ HardwareType Boot::GetHardwareType() {
|
||||||
}
|
}
|
||||||
return static_cast<HardwareType>(out_val);
|
return static_cast<HardwareType>(out_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Boot::IsRecoveryBoot() {
|
||||||
|
u64 val = 0;
|
||||||
|
if (R_FAILED(splGetConfig(SplConfigItem_IsRecoveryBoot, &val))) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
return val != 0;
|
||||||
|
}
|
|
@ -65,7 +65,7 @@ struct AsyncOperationKey {
|
||||||
struct BootReasonValue {
|
struct BootReasonValue {
|
||||||
u8 power_intr;
|
u8 power_intr;
|
||||||
u8 rtc_intr;
|
u8 rtc_intr;
|
||||||
u8 _0x3;
|
u8 nv_erc;
|
||||||
u8 boot_reason;
|
u8 boot_reason;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
||||||
|
|
Loading…
Reference in a new issue