diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp index 8b8b105f0..760e9bf88 100644 --- a/libraries/libstratosphere/include/stratosphere.hpp +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -41,6 +41,7 @@ /* At this point, just include the rest alphabetically. */ /* TODO: Figure out optimal order. */ #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/cal.hpp b/libraries/libstratosphere/include/stratosphere/cal.hpp new file mode 100644 index 000000000..49df7ae1b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cal.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once + +#include diff --git a/libraries/libstratosphere/include/stratosphere/cal/cal_battery_api.hpp b/libraries/libstratosphere/include/stratosphere/cal/cal_battery_api.hpp new file mode 100644 index 000000000..e576c95f8 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cal/cal_battery_api.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +namespace ams::cal { + + Result GetBatteryVersion(u8 *out); + Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl.hpp b/libraries/libstratosphere/include/stratosphere/powctl.hpp index 02d421952..3f293ccd5 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl.hpp @@ -20,4 +20,7 @@ #include #include #include +#include #include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp new file mode 100644 index 000000000..5aad9f116 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include +#include + +namespace ams::powctl::driver::impl { + + class ChargeArbiter { + private: + const ChargeParametersRule *rules; + size_t num_rules; + int charge_voltage_limit; + BatteryTemperatureLevel temperature_level; + int avg_v_cell; + int open_circuit_voltage; + bool has_battery_done_current; + int battery_done_current; + PowerState power_state; + const ChargeParametersRule *selected_rule; + bool check_battery_done_current; + private: + static constexpr bool IsInRange(int value, int min, int max) { + if (!(min <= value)) { + return false; + } + + if (max == std::numeric_limits::max()) { + return value <= max; + } else { + return value < max; + } + } + + bool IsAcceptablePowerState(const PowerState *acceptable, size_t num_acceptable) const { + for (size_t i = 0; i < num_acceptable; ++i) { + if (this->power_state == acceptable[i]) { + return true; + } + } + return false; + } + public: + ChargeArbiter(const ChargeParametersRule *r, size_t nr, int cvl) + : rules(r), num_rules(nr), charge_voltage_limit(cvl), temperature_level(BatteryTemperatureLevel::Medium), + avg_v_cell(4080), open_circuit_voltage(4001), has_battery_done_current(false), battery_done_current(0), + power_state(PowerState::FullAwake), selected_rule(nullptr), check_battery_done_current(false) + { + this->UpdateSelectedRule(); + } + + void SetBatteryTemperatureLevel(BatteryTemperatureLevel btl) { + this->temperature_level = btl; + this->UpdateSelectedRule(); + } + + void SetBatteryAverageVCell(int avg) { + this->avg_v_cell = avg; + this->UpdateSelectedRule(); + } + + void SetBatteryOpenCircuitVoltage(int ocv) { + this->open_circuit_voltage = ocv; + this->UpdateSelectedRule(); + } + + void SetBatteryDoneCurrent(int current) { + this->battery_done_current = current; + this->has_battery_done_current = true; + this->UpdateSelectedRule(); + } + + void SetPowerState(PowerState ps) { + this->power_state = ps; + this->UpdateSelectedRule(); + } + + int GetChargeVoltageLimit() const { + return this->charge_voltage_limit; + } + + bool IsBatteryDoneCurrentAcceptable(int current) const { + const auto *rule = this->GetSelectedRule(); + AMS_ASSERT(rule != nullptr); + + return IsInRange(0, rule->min_battery_done_current, rule->max_battery_done_current); + } + + const ChargeParametersRule *GetSelectedRule() const { + return this->selected_rule; + } + + void UpdateSelectedRule() { + /* Try to find an entry that fits our current requirements. */ + const ChargeParametersRule *best_rule = nullptr; + for (size_t i = 0; i < this->num_rules; ++i) { + /* Get the current rule. */ + const ChargeParametersRule &cur_rule = this->rules[i]; + + /* Check the temperature level. */ + if (this->temperature_level != cur_rule.temperature_level) { + continue; + } + + /* Check that average voltage is in range. */ + if (!IsInRange(this->avg_v_cell, cur_rule.min_avg_v_cell, cur_rule.max_avg_v_cell)) { + continue; + } + + /* Check that open circuit voltage is in range. */ + if (!IsInRange(this->open_circuit_voltage, cur_rule.min_open_circuit_voltage, cur_rule.max_open_circuit_voltage)) { + continue; + } + + /* Check if our power state is acceptable. */ + if (!this->IsAcceptablePowerState(cur_rule.acceptable_power_states, cur_rule.num_acceptable_power_states)) { + continue; + } + + /* The limit is probably acceptable. */ + if (this->selected_rule != std::addressof(cur_rule)) { + /* We're selecting a new rule. Check if our need to deal with battery current is acceptable. */ + if (cur_rule.check_battery_current && this->check_battery_done_current) { + continue; + } + + /* Set whether we need to check the battery done current. */ + this->has_battery_done_current = false; + this->check_battery_done_current |= cur_rule.check_battery_current; + } else { + /* We're selecting the currently selected rule. Make sure the battery done current is acceptable if we have one. */ + if (this->has_battery_done_current && !IsInRange(this->battery_done_current, cur_rule.min_battery_done_current, cur_rule.max_battery_done_current)) { + continue; + } + } + + /* Select the current rule. */ + best_rule = std::addressof(cur_rule); + break; + } + + /* Update our selected rule. */ + this->selected_rule = best_rule; + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp new file mode 100644 index 000000000..ed517587a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include + +namespace ams::powctl::driver::impl { + + struct ChargeParametersRule { + BatteryTemperatureLevel temperature_level; + int min_avg_v_cell; + int max_avg_v_cell; + int min_open_circuit_voltage; + int max_open_circuit_voltage; + int min_battery_done_current; + int max_battery_done_current; + const PowerState *acceptable_power_states; + size_t num_acceptable_power_states; + bool check_battery_current; + bool reinitialize_charger; + int charge_voltage_limit; + int fast_charge_current_limit; + int battery_compensation; + int voltage_clamp; + }; + + struct UnknownParameterX { + int _00; + int _04; + double _08; + double _10; + }; + + struct ChargeParameters { + int temp_min; + int temp_low; + int temp_high; + int temp_max; + int low_voltage_fast_charge_current_limit; + int default_charge_voltage_limit; + const UnknownParameterX *unknown_x_table; + size_t x_table_size; + double _28; + double _30; + const ChargeParametersRule *rules; + size_t num_rules; + }; + + const ChargeParameters &GetChargeParameters(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp new file mode 100644 index 000000000..80ba52636 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include + +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + + #include + +#else + #error "unknown board for powctl::driver::impl::ChargerParameters" +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp b/libraries/libstratosphere/include/stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp new file mode 100644 index 000000000..0ca9951ea --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include + +namespace ams::powctl::impl { + + constexpr inline const double MinRawDefaultPercentage = 3.0; + constexpr inline const double MaxRawDefaultPercentage = 99.0; + + constexpr inline const double MinRawThresholdPercentage = 11.0; + + constexpr inline const int MinDisplayPercentage = 1; + constexpr inline const int MaxDisplayPercentage = 100; + + constexpr inline void CalculateMarginatedRawPercentage(double *out_marginated_min, double *out_marginated_max, double min, double max) { + /* Ensure minimum is in correct range. */ + min = std::max(std::min(min, MinRawThresholdPercentage), MinRawDefaultPercentage); + + /* Calculate the marginated values. */ + constexpr const double MinMarginPercentage = 0.93359375; + constexpr const double MaxMarginPercentage = -0.83593750; + + const auto margin_factor = (max - min) / (MaxRawDefaultPercentage - MinRawDefaultPercentage); + *out_marginated_min = min + MinMarginPercentage * margin_factor; + *out_marginated_max = max + MaxMarginPercentage * margin_factor; + } + + constexpr inline int GetDisplayPercentage(double raw_percentage, double min, double max) { + /* Calculate the display percentage. */ + constexpr const double BaseDisplayPercentage = 2.0; + const auto display_percentage = BaseDisplayPercentage + ((static_cast(MaxDisplayPercentage - MinDisplayPercentage) * (raw_percentage - min)) / (max - min)); + + /* Clamp the display percentage within bounds. */ + return std::max(std::min(static_cast(display_percentage), MaxDisplayPercentage), MinDisplayPercentage); + } + + constexpr inline int ConvertBatteryChargePercentage(double raw_percentage, double min, double max) { + /* Marginate the min/max. */ + double marginated_min = 0.0, marginated_max = 0.0; + CalculateMarginatedRawPercentage(std::addressof(marginated_min), std::addressof(marginated_max), min, max); + + /* Convert to display percentage. */ + return GetDisplayPercentage(raw_percentage, marginated_min, marginated_max); + } + + constexpr inline int ConvertBatteryChargePercentage(double raw_percentage) { + return ConvertBatteryChargePercentage(raw_percentage, MinRawDefaultPercentage, MaxRawDefaultPercentage); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp index 1b74f6fbc..60dd0788f 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp @@ -25,15 +25,15 @@ namespace ams::powctl { Result GetBatterySocVf(float *out_percent, Session &session); - Result GetBatteryFullCapacity(u32 *out_mah, Session &session); - Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session); + Result GetBatteryFullCapacity(int *out_mah, Session &session); + Result GetBatteryRemainingCapacity(int *out_mah, Session &session); Result SetBatteryPercentageMinimumAlertThreshold(Session &session, float percentage); Result SetBatteryPercentageMaximumAlertThreshold(Session &session, float percentage); Result SetBatteryPercentageFullThreshold(Session &session, float percentage); - Result GetBatteryAverageCurrent(u32 *out_ma, Session &session); - Result GetBatteryCurrent(u32 *out_ma, Session &session); + Result GetBatteryAverageCurrent(int *out_ma, Session &session); + Result GetBatteryCurrent(int *out_ma, Session &session); Result GetBatteryInternalState(void *dst, size_t *out_size, Session &session, size_t dst_size); Result SetBatteryInternalState(Session &session, const void *src, size_t src_size); @@ -44,10 +44,10 @@ namespace ams::powctl { Result IsBatteryI2cShutdownEnabled(bool *out, Session &session); Result SetBatteryI2cShutdownEnabled(Session &session, bool en); - Result IsBatteryRemoved(bool *out, Session &session); + Result IsBatteryPresent(bool *out, Session &session); - Result GetBatteryCycles(u32 *out, Session &session); - Result SetBatteryCycles(Session &session, u32 cycles); + Result GetBatteryCycles(int *out, Session &session); + Result SetBatteryCycles(Session &session, int cycles); Result GetBatteryAge(float *out_percent, Session &session); @@ -57,14 +57,14 @@ namespace ams::powctl { Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c); Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c); - Result GetBatteryVCell(u32 *out_mv, Session &session); - Result GetBatteryAverageVCell(u32 *out_mv, Session &session); + Result GetBatteryVCell(int *out_mv, Session &session); + Result GetBatteryAverageVCell(int *out_mv, Session &session); Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session); - Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session); + Result GetBatteryOpenCircuitVoltage(int *out_mv, Session &session); - Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv); - Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv); + Result SetBatteryVoltageMinimumAlertThreshold(Session &session, int mv); + Result SetBatteryVoltageMaximumAlertThreshold(Session &session, int mv); } diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp index acc6c1064..c7a53068d 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp @@ -24,22 +24,22 @@ namespace ams::powctl { Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session); Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state); - Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session); - Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma); + Result GetChargerFastChargeCurrentLimit(int *out_ma, Session &session); + Result SetChargerFastChargeCurrentLimit(Session &session, int ma); - Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session); - Result SetChargerChargeVoltageLimit(Session &session, u32 mv); + Result GetChargerChargeVoltageLimit(int *out_mv, Session &session); + Result SetChargerChargeVoltageLimit(Session &session, int mv); Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg); Result IsChargerHiZEnabled(bool *out, Session &session); Result SetChargerHiZEnabled(Session &session, bool en); - Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session); - Result SetChargerInputCurrentLimit(Session &session, u32 ma); + Result GetChargerInputCurrentLimit(int *out_ma, Session &session); + Result SetChargerInputCurrentLimit(Session &session, int ma); - Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session); - Result SetChargerInputVoltageLimit(Session &session, u32 mv); + Result GetChargerInputVoltageLimit(int *out_mv, Session &session); + Result SetChargerInputVoltageLimit(Session &session, int mv); Result GetChargerChargerStatus(ChargerStatus *out, Session &session); @@ -49,10 +49,10 @@ namespace ams::powctl { Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout); Result ResetChargerWatchdogTimer(Session &session); - Result GetChargerBatteryCompensation(u32 *out_mo, Session &session); - Result SetChargerBatteryCompensation(Session &session, u32 mo); + Result GetChargerBatteryCompensation(int *out_mo, Session &session); + Result SetChargerBatteryCompensation(Session &session, int mo); - Result GetChargerVoltageClamp(u32 *out_mv, Session &session); - Result SetChargerVoltageClamp(Session &session, u32 mv); + Result GetChargerVoltageClamp(int *out_mv, Session &session); + Result SetChargerVoltageClamp(Session &session, int mv); } diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp index 3a3538bb9..ae65dbe13 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp @@ -27,9 +27,9 @@ namespace ams::powctl { }; enum ChargerConfiguration { - ChargerConfiguration_ChargeDisable = 0, - ChargerConfiguration_ChargeBattery = 1, - ChargerConfiguration_Otg = 2, + ChargerConfiguration_ChargeDisable = 1, + ChargerConfiguration_ChargeBattery = 2, + ChargerConfiguration_Otg = 3, }; enum ChargeCurrentState { @@ -38,4 +38,20 @@ namespace ams::powctl { ChargeCurrentState_Charging = 0x3, }; + enum class BatteryTemperatureLevel { + TooLow = 0, + Low = 1, + Medium = 2, + High = 3, + TooHigh = 4, + }; + + enum class PowerState { + FullAwake = 0, + MinimumAwake = 1, + SleepCharge = 2, + SleepDischarge = 3, + ShutdownChargeMain = 4, + }; + } \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp b/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp index 6232c3ee0..1225cd6e7 100644 --- a/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp @@ -150,6 +150,15 @@ namespace ams::spl { }; }; static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); + + enum BootReason { + BootReason_Unknown = 0, + BootReason_AcOk = 1, + BootReason_OnKey = 2, + BootReason_RtcAlarm1 = 3, + BootReason_RtcAlarm2 = 4, + }; + #pragma pack(push, 1) struct AesKey { diff --git a/libraries/libstratosphere/source/cal/cal_battery_api.cpp b/libraries/libstratosphere/source/cal/cal_battery_api.cpp new file mode 100644 index 000000000..3de3dce60 --- /dev/null +++ b/libraries/libstratosphere/source/cal/cal_battery_api.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "cal_fs_utils.hpp" + +namespace ams::cal { + + namespace { + + constexpr inline s64 BatteryLotOffset = 0x2CE0; + constexpr inline size_t BatteryLotSize = 0x20; + + constexpr inline s64 BatteryVersionOffset = 0x4310; + constexpr inline size_t BatteryVersionSize = 0x10; + + constexpr inline size_t BatteryVendorSizeMax = 0x18; + + } + + Result GetBatteryVersion(u8 *out) { + /* Read the battery version. */ + u8 battery_version[BatteryVersionSize]; + R_TRY(cal::impl::ReadCalibrationBlock(BatteryVersionOffset, battery_version, sizeof(battery_version))); + + /* Write the output. */ + *out = battery_version[0]; + return ResultSuccess(); + } + + Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size) { + /* Read the battery lot. */ + char battery_lot[BatteryLotSize]; + R_TRY(cal::impl::ReadCalibrationBlock(BatteryLotOffset, battery_lot, sizeof(battery_lot))); + + /* Copy output. */ + *out_vendor_size = static_cast(util::Strlcpy(static_cast(dst), battery_lot, std::min(dst_size, BatteryVendorSizeMax))); + return ResultSuccess(); + } + +} diff --git a/libraries/libstratosphere/source/cal/cal_crc_utils.cpp b/libraries/libstratosphere/source/cal/cal_crc_utils.cpp new file mode 100644 index 000000000..811aa37db --- /dev/null +++ b/libraries/libstratosphere/source/cal/cal_crc_utils.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "cal_crc_utils.hpp" + +namespace ams::cal::impl { + + namespace { + + constexpr inline const u16 CrcTable[0x10] = { + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 + }; + + } + + u16 CalculateCrc16(const void *data, size_t size) { + AMS_ASSERT(data != nullptr); + + u16 crc = 0x55AA; + const u8 *data_u8 = static_cast(data); + for (size_t i = 0; i < size; ++i) { + crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 0) & 0xF]); + crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 4) & 0xF]); + } + + return crc; + } + + Result ValidateCalibrationCrc(const void *data, size_t size) { + AMS_ASSERT(data != nullptr); + AMS_ASSERT(size >= sizeof(u16)); + + const u16 crc = *reinterpret_cast(reinterpret_cast(data) + size - sizeof(u16)); + R_UNLESS(CalculateCrc16(data, size - sizeof(u16)) == crc, cal::ResultCalibrationDataCrcError()); + + return ResultSuccess(); + } + +} diff --git a/stratosphere/boot/source/boot_pmc_wrapper.hpp b/libraries/libstratosphere/source/cal/cal_crc_utils.hpp similarity index 70% rename from stratosphere/boot/source/boot_pmc_wrapper.hpp rename to libraries/libstratosphere/source/cal/cal_crc_utils.hpp index 5be8103f6..2e2c4f857 100644 --- a/stratosphere/boot/source/boot_pmc_wrapper.hpp +++ b/libraries/libstratosphere/source/cal/cal_crc_utils.hpp @@ -16,12 +16,9 @@ #pragma once #include -namespace ams::boot { +namespace ams::cal::impl { - constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400; - - /* PMC Access Utilities. */ - u32 ReadPmcRegister(dd::PhysicalAddress phys_addr); - void WritePmcRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask = std::numeric_limits::max()); + u16 CalculateCrc16(const void *data, size_t size); + Result ValidateCalibrationCrc(const void *data, size_t size); } diff --git a/libraries/libstratosphere/source/cal/cal_fs_utils.cpp b/libraries/libstratosphere/source/cal/cal_fs_utils.cpp new file mode 100644 index 000000000..70e58bcb6 --- /dev/null +++ b/libraries/libstratosphere/source/cal/cal_fs_utils.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "cal_crc_utils.hpp" +#include "cal_fs_utils.hpp" + +namespace ams::cal::impl { + + Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size) { + /* Open the calibration binary partition. */ + std::unique_ptr storage; + R_TRY(fs::OpenBisPartition(std::addressof(storage), fs::BisPartitionId::CalibrationBinary)); + + /* Read data from the partition. */ + R_TRY(storage->Read(offset, dst, block_size)); + + /* Validate the crc. */ + R_TRY(ValidateCalibrationCrc(dst, block_size)); + + return ResultSuccess(); + } + +} diff --git a/stratosphere/boot/source/boot_calibration.hpp b/libraries/libstratosphere/source/cal/cal_fs_utils.hpp similarity index 86% rename from stratosphere/boot/source/boot_calibration.hpp rename to libraries/libstratosphere/source/cal/cal_fs_utils.hpp index d8dd1f5b1..2bea0fe4d 100644 --- a/stratosphere/boot/source/boot_calibration.hpp +++ b/libraries/libstratosphere/source/cal/cal_fs_utils.hpp @@ -16,10 +16,8 @@ #pragma once #include -namespace ams::boot { +namespace ams::cal::impl { - /* Calibration utilities. */ - u32 GetBatteryVersion(); - u32 GetBatteryVendor(); + Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size); } diff --git a/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.cpp b/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.cpp new file mode 100644 index 000000000..aa49183be --- /dev/null +++ b/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::powctl::driver::impl { + + namespace { + + constexpr inline const PowerState AcceptablePowerStates[] = { + PowerState::FullAwake, + PowerState::MinimumAwake, + PowerState::SleepCharge, + PowerState::SleepDischarge, + PowerState::ShutdownChargeMain, + }; + + constexpr inline const PowerState AcceptablePowerStatesForNotAwakeCharge[] = { + PowerState::SleepCharge, + PowerState::ShutdownChargeMain, + }; + + constexpr inline const int Min = std::numeric_limits::min(); + constexpr inline const int Max = std::numeric_limits::max(); + + constexpr inline const UnknownParameterX UnknownXTableForBatteryVersion2[] = { + { 20000, 4320, 95.0, 100.4 }, + { 30000, 4304, 94.0, 99.7 }, + { 40000, 4288, 93.0, 98.4 }, + { 50000, 4272, 92.0, 97.0 }, + { 60000, 4256, 90.0, 95.7 }, + { 80000, 4240, 89.0, 94.2 }, + { 100000, 4224, 88.0, 93.0 }, + { Max, 4192, 85.0, 90.0 }, + }; + + /* Include automatically extracted charger parameters. */ + #include "powctl_charger_parameters.board.nintendo_nx.inc" + + } + + const ChargeParameters &GetChargeParameters() { + /* Get the battery version. */ + u8 battery_version; + if (R_FAILED(cal::GetBatteryVersion(std::addressof(battery_version)))) { + battery_version = 0; + } + + if (battery_version == 2) { + return ChargeParametersForBatteryVersion2; + } else if (battery_version == 1) { + return ChargeParametersForBatteryVersion1; + } else { + if (spl::GetHardwareType() == spl::HardwareType::_Five_) { + return ChargeParametersForBatteryVersion0ForFive; + } else { + return ChargeParametersForBatteryVersion0; + } + } + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.inc b/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.inc new file mode 100644 index 000000000..70f86ac09 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.inc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +/* NOTE: This file is auto-generated by charger_parameters.py, do not edit manually. */ + +constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion0[] = { + { BatteryTemperatureLevel::TooLow, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 512, 0, 0 }, + { BatteryTemperatureLevel::TooLow, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 768, 0, 0 }, + { BatteryTemperatureLevel::Low, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 512, 0, 0 }, + { BatteryTemperatureLevel::Low, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 768, 0, 0 }, + { BatteryTemperatureLevel::Medium, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 512, 0, 0 }, + { BatteryTemperatureLevel::Medium, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 2048, 0, 0 }, + { BatteryTemperatureLevel::High, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 512, 0, 0 }, + { BatteryTemperatureLevel::High, 3320, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 2048, 0, 0 }, + { BatteryTemperatureLevel::High, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 512, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, 3320, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 2048, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 }, +}; + +constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion1[] = { + { BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 576, 0, 0 }, + { BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 576, 0, 0 }, + { BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 1536, 0, 0 }, + { BatteryTemperatureLevel::High, Min, 3984, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3984, 1536, 0, 0 }, + { BatteryTemperatureLevel::High, 3984, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 1536, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, Min, 3984, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3984, 1536, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, 3984, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 1536, 0, 0 }, +}; + +constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion2[] = { + { BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 640, 0, 0 }, + { BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4320, 640, 0, 0 }, + { BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4320, 1664, 0, 0 }, + { BatteryTemperatureLevel::High, Min, 4080, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4080, 1664, 0, 0 }, + { BatteryTemperatureLevel::High, 4080, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 1664, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, Min, 4080, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4080, 1664, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, 4080, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 1664, 0, 0 }, +}; + +constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion0ForFive[] = { + { BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 768, 0, 0 }, + { BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 768, 0, 0 }, + { BatteryTemperatureLevel::Medium, Min, Max, Min, 4001, 2049, Max, AcceptablePowerStatesForNotAwakeCharge, util::size(AcceptablePowerStatesForNotAwakeCharge), true, true, 4000, 3072, 40, 112 }, + { BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 2048, 0, 0 }, + { BatteryTemperatureLevel::High, Min, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 2048, 0, 0 }, + { BatteryTemperatureLevel::High, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, Min, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 2048, 0, 0 }, + { BatteryTemperatureLevel::TooHigh, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 }, +}; + +constexpr inline const ChargeParameters ChargeParametersForBatteryVersion0 = { + 4, 17, 51, 60, 512, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion0, util::size(ChargeParametersRulesForBatteryVersion0) +}; + +constexpr inline const ChargeParameters ChargeParametersForBatteryVersion1 = { + 1, 19, 48, 59, 1536, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion1, util::size(ChargeParametersRulesForBatteryVersion1) +}; + +constexpr inline const ChargeParameters ChargeParametersForBatteryVersion2 = { + 1, 19, 48, 59, 1664, 4320, UnknownXTableForBatteryVersion2, util::size(UnknownXTableForBatteryVersion2), 95.0, 100.4, ChargeParametersRulesForBatteryVersion2, util::size(ChargeParametersRulesForBatteryVersion2) +}; + +constexpr inline const ChargeParameters ChargeParametersForBatteryVersion0ForFive = { + 4, 17, 51, 60, 512, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion0ForFive, util::size(ChargeParametersRulesForBatteryVersion0ForFive) +}; diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp deleted file mode 100644 index c9a31a707..000000000 --- a/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2018-2020 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 . - */ -#pragma once -#include - -namespace ams::powctl::impl { - - class IDevice : public ::ams::ddsf::IDevice { - NON_COPYABLE(IDevice); - NON_MOVEABLE(IDevice); - AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IDevice, ::ams::ddsf::IDevice); - public: - IDevice() : ddsf::IDevice(false) { /* ... */ } - virtual ~IDevice() { /* ... */ } - }; - - class IPowerControlDriver : public ::ams::ddsf::IDriver { - NON_COPYABLE(IPowerControlDriver); - NON_MOVEABLE(IPowerControlDriver); - AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IPowerControlDriver, ::ams::ddsf::IDriver); - private: - bool event_handler_enabled; - protected: - constexpr bool IsEventHandlerEnabled() const { - return this->event_handler_enabled; - } - public: - IPowerControlDriver(bool ev) : IDriver(), event_handler_enabled(ev) { /* ... */ } - virtual ~IPowerControlDriver() { /* ... */ } - - virtual void InitializeDriver() = 0; - virtual void FinalizeDriver() = 0; - - virtual Result GetDeviceSystemEvent(IDevice *device) = 0; - virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) = 0; - - /* TODO: Eventually implement proper error status enum? */ - virtual Result GetDeviceErrorStatus(u32 *out, IDevice *device) = 0; - virtual Result SetDeviceErrorStatus(IDevice *device, u32 status) = 0; - - virtual Result GetBatterySocRep(float *out_percent, IDevice *device) = 0; - - virtual Result GetBatterySocVf(float *out_percent, IDevice *device) = 0; - - virtual Result GetBatteryFullCapacity(u32 *out_mah, IDevice *device) = 0; - virtual Result GetBatteryRemainingCapacity(u32 *out_mah, IDevice *device) = 0; - - virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0; - virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0; - virtual Result SetBatteryPercentageFullThreshold(IDevice *device, float percentage) = 0; - - virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0; - virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0; - - virtual Result GetChargerFastChargeCurrentLimit(u32 *out_ma, IDevice *device) = 0; - virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, u32 ma) = 0; - - virtual Result GetChargerChargeVoltageLimit(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerChargeVoltageLimit(IDevice *device, u32 mv) = 0; - - virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0; - - virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0; - virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0; - - virtual Result GetBatteryAverageCurrent(u32 *out_ma, IDevice *device) = 0; - virtual Result GetBatteryCurrent(u32 *out_ma, IDevice *device) = 0; - - virtual Result GetChargerInputCurrentLimit(u32 *out_ma, IDevice *device) = 0; - virtual Result SetChargerInputCurrentLimit(IDevice *device, u32 ma) = 0; - - virtual Result GetChargerInputVoltageLimit(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerInputVoltageLimit(IDevice *device, u32 mv) = 0; - - virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) = 0; - virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) = 0; - - virtual Result GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) = 0; - virtual Result SetBatteryNeedToRestoreParameters(IDevice *device, bool en) = 0; - - virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0; - virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0; - - virtual Result IsBatteryRemoved(bool *out, IDevice *device) = 0; - - virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0; - - virtual Result GetBatteryCycles(u32 *out, IDevice *device) = 0; - virtual Result SetBatteryCycles(IDevice *device, u32 cycles) = 0; - - virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0; - - virtual Result GetBatteryTemperature(float *out_c, IDevice *device) = 0; - virtual Result GetBatteryMaximumTemperature(float *out_c, IDevice *device) = 0; - - virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0; - virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0; - - virtual Result GetBatteryVCell(u32 *out_mv, IDevice *device) = 0; - virtual Result GetBatteryAverageVCell(u32 *out_mv, IDevice *device) = 0; - - virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0; - - virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, u32 mv) = 0; - - virtual Result GetBatteryOpenCircuitVoltage(u32 *out_mv, IDevice *device) = 0; - - virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, u32 mv) = 0; - - virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0; - virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0; - - virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0; - virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0; - - virtual Result GetChargerBatteryCompensation(u32 *out_mo, IDevice *device) = 0; - virtual Result SetChargerBatteryCompensation(IDevice *device, u32 mo) = 0; - - virtual Result GetChargerVoltageClamp(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerVoltageClamp(IDevice *device, u32 mv) = 0; - }; - -} diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp index c9a31a707..fc4e1ee55 100644 --- a/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp +++ b/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp @@ -55,8 +55,8 @@ namespace ams::powctl::impl { virtual Result GetBatterySocVf(float *out_percent, IDevice *device) = 0; - virtual Result GetBatteryFullCapacity(u32 *out_mah, IDevice *device) = 0; - virtual Result GetBatteryRemainingCapacity(u32 *out_mah, IDevice *device) = 0; + virtual Result GetBatteryFullCapacity(int *out_mah, IDevice *device) = 0; + virtual Result GetBatteryRemainingCapacity(int *out_mah, IDevice *device) = 0; virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0; virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0; @@ -65,25 +65,25 @@ namespace ams::powctl::impl { virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0; virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0; - virtual Result GetChargerFastChargeCurrentLimit(u32 *out_ma, IDevice *device) = 0; - virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, u32 ma) = 0; + virtual Result GetChargerFastChargeCurrentLimit(int *out_ma, IDevice *device) = 0; + virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, int ma) = 0; - virtual Result GetChargerChargeVoltageLimit(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerChargeVoltageLimit(IDevice *device, u32 mv) = 0; + virtual Result GetChargerChargeVoltageLimit(int *out_mv, IDevice *device) = 0; + virtual Result SetChargerChargeVoltageLimit(IDevice *device, int mv) = 0; virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0; virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0; virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0; - virtual Result GetBatteryAverageCurrent(u32 *out_ma, IDevice *device) = 0; - virtual Result GetBatteryCurrent(u32 *out_ma, IDevice *device) = 0; + virtual Result GetBatteryAverageCurrent(int *out_ma, IDevice *device) = 0; + virtual Result GetBatteryCurrent(int *out_ma, IDevice *device) = 0; - virtual Result GetChargerInputCurrentLimit(u32 *out_ma, IDevice *device) = 0; - virtual Result SetChargerInputCurrentLimit(IDevice *device, u32 ma) = 0; + virtual Result GetChargerInputCurrentLimit(int *out_ma, IDevice *device) = 0; + virtual Result SetChargerInputCurrentLimit(IDevice *device, int ma) = 0; - virtual Result GetChargerInputVoltageLimit(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerInputVoltageLimit(IDevice *device, u32 mv) = 0; + virtual Result GetChargerInputVoltageLimit(int *out_mv, IDevice *device) = 0; + virtual Result SetChargerInputVoltageLimit(IDevice *device, int mv) = 0; virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) = 0; virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) = 0; @@ -94,12 +94,12 @@ namespace ams::powctl::impl { virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0; virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0; - virtual Result IsBatteryRemoved(bool *out, IDevice *device) = 0; + virtual Result IsBatteryPresent(bool *out, IDevice *device) = 0; virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0; - virtual Result GetBatteryCycles(u32 *out, IDevice *device) = 0; - virtual Result SetBatteryCycles(IDevice *device, u32 cycles) = 0; + virtual Result GetBatteryCycles(int *out, IDevice *device) = 0; + virtual Result SetBatteryCycles(IDevice *device, int cycles) = 0; virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0; @@ -109,16 +109,16 @@ namespace ams::powctl::impl { virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0; virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0; - virtual Result GetBatteryVCell(u32 *out_mv, IDevice *device) = 0; - virtual Result GetBatteryAverageVCell(u32 *out_mv, IDevice *device) = 0; + virtual Result GetBatteryVCell(int *out_mv, IDevice *device) = 0; + virtual Result GetBatteryAverageVCell(int *out_mv, IDevice *device) = 0; virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0; - virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, u32 mv) = 0; + virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, int mv) = 0; - virtual Result GetBatteryOpenCircuitVoltage(u32 *out_mv, IDevice *device) = 0; + virtual Result GetBatteryOpenCircuitVoltage(int *out_mv, IDevice *device) = 0; - virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, u32 mv) = 0; + virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, int mv) = 0; virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0; virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0; @@ -126,11 +126,11 @@ namespace ams::powctl::impl { virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0; virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0; - virtual Result GetChargerBatteryCompensation(u32 *out_mo, IDevice *device) = 0; - virtual Result SetChargerBatteryCompensation(IDevice *device, u32 mo) = 0; + virtual Result GetChargerBatteryCompensation(int *out_mo, IDevice *device) = 0; + virtual Result SetChargerBatteryCompensation(IDevice *device, int mo) = 0; - virtual Result GetChargerVoltageClamp(u32 *out_mv, IDevice *device) = 0; - virtual Result SetChargerVoltageClamp(IDevice *device, u32 mv) = 0; + virtual Result GetChargerVoltageClamp(int *out_mv, IDevice *device) = 0; + virtual Result SetChargerVoltageClamp(IDevice *device, int mv) = 0; }; } diff --git a/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp b/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp index ba16bb4aa..0be40c083 100644 --- a/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp +++ b/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp @@ -58,7 +58,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatterySocVf(out_percent, std::addressof(device)); } - Result GetBatteryFullCapacity(u32 *out_mah, Session &session) { + Result GetBatteryFullCapacity(int *out_mah, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -72,7 +72,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryFullCapacity(out_mah, std::addressof(device)); } - Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session) { + Result GetBatteryRemainingCapacity(int *out_mah, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -128,7 +128,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetBatteryPercentageFullThreshold(std::addressof(device), percentage); } - Result GetBatteryAverageCurrent(u32 *out_ma, Session &session) { + Result GetBatteryAverageCurrent(int *out_ma, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -142,7 +142,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryAverageCurrent(out_ma, std::addressof(device)); } - Result GetBatteryCurrent(u32 *out_ma, Session &session) { + Result GetBatteryCurrent(int *out_ma, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -240,7 +240,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetBatteryI2cShutdownEnabled(std::addressof(device), en); } - Result IsBatteryRemoved(bool *out, Session &session) { + Result IsBatteryPresent(bool *out, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -251,10 +251,10 @@ namespace ams::powctl { auto &device = impl.GetDevice().SafeCastTo(); /* Call into the driver. */ - return device.GetDriver().SafeCastTo().IsBatteryRemoved(out, std::addressof(device)); + return device.GetDriver().SafeCastTo().IsBatteryPresent(out, std::addressof(device)); } - Result GetBatteryCycles(u32 *out, Session &session) { + Result GetBatteryCycles(int *out, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -268,7 +268,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryCycles(out, std::addressof(device)); } - Result SetBatteryCycles(Session &session, u32 cycles) { + Result SetBatteryCycles(Session &session, int cycles) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -352,7 +352,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetBatteryTemperatureMaximumAlertThreshold(std::addressof(device), c); } - Result GetBatteryVCell(u32 *out_mv, Session &session) { + Result GetBatteryVCell(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -366,7 +366,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryVCell(out_mv, std::addressof(device)); } - Result GetBatteryAverageVCell(u32 *out_mv, Session &session) { + Result GetBatteryAverageVCell(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -394,7 +394,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryAverageVCellTime(out, std::addressof(device)); } - Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session) { + Result GetBatteryOpenCircuitVoltage(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -408,7 +408,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetBatteryOpenCircuitVoltage(out_mv, std::addressof(device)); } - Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv) { + Result SetBatteryVoltageMinimumAlertThreshold(Session &session, int mv) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -422,7 +422,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetBatteryVoltageMinimumAlertThreshold(std::addressof(device), mv); } - Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv) { + Result SetBatteryVoltageMaximumAlertThreshold(Session &session, int mv) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); diff --git a/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp b/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp index eb9fbff65..7744c9193 100644 --- a/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp +++ b/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp @@ -58,7 +58,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetChargerChargeCurrentState(std::addressof(device), state); } - Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session) { + Result GetChargerFastChargeCurrentLimit(int *out_ma, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -72,7 +72,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerFastChargeCurrentLimit(out_ma, std::addressof(device)); } - Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma) { + Result SetChargerFastChargeCurrentLimit(Session &session, int ma) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -86,7 +86,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetChargerFastChargeCurrentLimit(std::addressof(device), ma); } - Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session) { + Result GetChargerChargeVoltageLimit(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -100,7 +100,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerChargeVoltageLimit(out_mv, std::addressof(device)); } - Result SetChargerChargeVoltageLimit(Session &session, u32 mv) { + Result SetChargerChargeVoltageLimit(Session &session, int mv) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -156,7 +156,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetChargerHiZEnabled(std::addressof(device), en); } - Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session) { + Result GetChargerInputCurrentLimit(int *out_ma, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -170,7 +170,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerInputCurrentLimit(out_ma, std::addressof(device)); } - Result SetChargerInputCurrentLimit(Session &session, u32 ma) { + Result SetChargerInputCurrentLimit(Session &session, int ma) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -184,7 +184,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetChargerInputCurrentLimit(std::addressof(device), ma); } - Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session) { + Result GetChargerInputVoltageLimit(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -198,7 +198,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerInputVoltageLimit(out_mv, std::addressof(device)); } - Result SetChargerInputVoltageLimit(Session &session, u32 mv) { + Result SetChargerInputVoltageLimit(Session &session, int mv) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -270,7 +270,7 @@ namespace ams::powctl { Result ResetChargerWatchdogTimer(Session &session); - Result GetChargerBatteryCompensation(u32 *out_mo, Session &session) { + Result GetChargerBatteryCompensation(int *out_mo, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -284,7 +284,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerBatteryCompensation(out_mo, std::addressof(device)); } - Result SetChargerBatteryCompensation(Session &session, u32 mo) { + Result SetChargerBatteryCompensation(Session &session, int mo) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -298,7 +298,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().SetChargerBatteryCompensation(std::addressof(device), mo); } - Result GetChargerVoltageClamp(u32 *out_mv, Session &session) { + Result GetChargerVoltageClamp(int *out_mv, Session &session) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); @@ -312,7 +312,7 @@ namespace ams::powctl { return device.GetDriver().SafeCastTo().GetChargerVoltageClamp(out_mv, std::addressof(device)); } - Result SetChargerVoltageClamp(Session &session, u32 mv) { + Result SetChargerVoltageClamp(Session &session, int mv) { /* Get the session impl. */ auto &impl = GetOpenSessionImpl(session); diff --git a/stratosphere/boot/source/boot_battery_driver.cpp b/stratosphere/boot/source/boot_battery_driver.cpp deleted file mode 100644 index ae6a5b776..000000000 --- a/stratosphere/boot/source/boot_battery_driver.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include "boot_battery_driver.hpp" -#include "boot_calibration.hpp" -#include "boot_i2c_utils.hpp" - -namespace ams::boot { - - /* Include configuration into anonymous namespace. */ - namespace { - -#include "boot_battery_parameters.inc" - - const Max17050Parameters *GetBatteryParameters() { - const u32 battery_version = GetBatteryVersion(); - const u32 battery_vendor = 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 ReadI2cRegister(this->i2c_session, reinterpret_cast(out), sizeof(*out), &addr, sizeof(addr)); - } - - Result BatteryDriver::Write(u8 addr, u16 val) { - return WriteI2cRegister(this->i2c_session, reinterpret_cast(&val), sizeof(val), &addr, sizeof(addr)); - } - - Result BatteryDriver::ReadWrite(u8 addr, u16 mask, u16 val) { - u16 cur_val; - R_TRY(this->Read(addr, &cur_val)); - - const u16 new_val = (cur_val & ~mask) | val; - R_TRY(this->Write(addr, new_val)); - - 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() { - R_TRY(this->Write(Max17050ModelAccess0, 0x0000)); - R_TRY(this->Write(Max17050ModelAccess1, 0x0000)); - return ResultSuccess(); - } - - Result BatteryDriver::UnlockModelTable() { - R_TRY(this->Write(Max17050ModelAccess0, 0x0059)); - R_TRY(this->Write(Max17050ModelAccess1, 0x00C4)); - return ResultSuccess(); - } - - Result BatteryDriver::SetModelTable(const u16 *model_table) { - for (size_t i = 0; i < Max17050ModelChrTblSize; i++) { - R_TRY(this->Write(Max17050ModelChrTblStart + i, model_table[i])); - } - 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(); - - if (IsPowerOnReset()) { - /* Do initial config. */ - R_TRY(this->ReadWrite(Max17050MiscCfg, 0x8000, 0x8000)); - - svcSleepThread(500'000'000ul); - - R_TRY(this->Write(Max17050Config, 0x7210)); - R_TRY(this->Write(Max17050FilterCfg, 0x8784)); - R_TRY(this->Write(Max17050RelaxCfg, params->relaxcfg)); - R_TRY(this->Write(Max17050LearnCfg, 0x2603)); - R_TRY(this->Write(Max17050FullSocThr, params->fullsocthr)); - R_TRY(this->Write(Max17050IAvgEmpty, params->iavgempty)); - - /* Unlock model table, write model table. */ - do { - R_TRY(this->UnlockModelTable()); - R_TRY(this->SetModelTable(params->modeltbl)); - } while (!this->IsModelTableSet(params->modeltbl)); - - /* Lock model table. */ - size_t lock_i = 0; - while (true) { - lock_i++; - R_TRY(this->LockModelTable()); - - 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)) { /* ... */ } - - R_TRY(this->Write(Max17050IChgTerm, params->ichgterm)); - R_TRY(this->Write(Max17050TGain, params->tgain)); - R_TRY(this->Write(Max17050TOff, params->toff)); - - 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)) { /* ... */ } - R_TRY(this->Write(Max17050DesignCap, params->vffullcap)); - while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ } - - svcSleepThread(350'000'000ul); - - /* Write VFSOC to VFSOC 0. */ - u16 vfsoc, qh; - { - R_TRY(this->Read(Max17050SocVf, &vfsoc)); - R_TRY(this->UnlockVfSoc()); - R_TRY(this->Write(Max17050SocVf0, vfsoc)); - R_TRY(this->Read(Max17050Qh, &qh)); - R_TRY(this->Write(Max17050Qh0, qh)); - R_TRY(this->LockVfSoc()); - } - - /* Write cycles. */ - while (!this->WriteValidate(Max17050Cycles, 0x0060)) { /* ... */ } - - /* Load new capacity parameters. */ - const u16 remcap = static_cast((vfsoc * params->vffullcap) / 0x6400); - const u16 repcap = static_cast(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)) { /* ... */ } - R_TRY(this->Write(Max17050DesignCap, params->vffullcap)); - while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ } - R_TRY(this->Write(Max17050SocRep, vfsoc)); - - /* Finish initialization. */ - { - u16 status; - R_TRY(this->Read(Max17050Status, &status)); - while (!this->WriteValidate(Max17050Status, status & 0xFFFD)) { /* ... */ } - } - R_TRY(this->Write(Max17050CGain, 0x7FFF)); - } - - return ResultSuccess(); - } - - Result BatteryDriver::IsBatteryRemoved(bool *out) { - /* N doesn't check result, but we will. */ - u16 val = 0; - R_TRY(this->Read(Max17050Status, &val)); - *out = (val & 0x0008) == 0x0008; - return ResultSuccess(); - } - - Result BatteryDriver::GetTemperature(double *out) { - u16 val = 0; - R_TRY(this->Read(Max17050Temperature, &val)); - *out = static_cast(val) * double(0.00390625); - return ResultSuccess(); - } - - Result BatteryDriver::GetAverageVCell(u32 *out) { - u16 val = 0; - R_TRY(this->Read(Max17050AverageVCell, &val)); - *out = (625 * u32(val >> 3)) / 1000; - return ResultSuccess(); - } - - Result BatteryDriver::GetSocRep(double *out) { - u16 val = 0; - R_TRY(this->Read(Max17050SocRep, &val)); - *out = static_cast(val) * double(0.00390625); - return ResultSuccess(); - } - - Result BatteryDriver::GetBatteryPercentage(size_t *out) { - double raw_charge; - R_TRY(this->GetSocRep(&raw_charge)); - 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(converted_percentage); - } - return ResultSuccess(); - } - - Result BatteryDriver::SetShutdownTimer() { - return this->Write(Max17050ShdnTimer, 0xE000); - } - - Result BatteryDriver::GetShutdownEnabled(bool *out) { - u16 val = 0; - R_TRY(this->Read(Max17050Config, &val)); - *out = (val & 0x0040) != 0; - return ResultSuccess(); - } - - Result BatteryDriver::SetShutdownEnabled(bool enabled) { - return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000); - } - -} diff --git a/stratosphere/boot/source/boot_battery_driver.hpp b/stratosphere/boot/source/boot_battery_driver.hpp index 688b1754b..c1c889a29 100644 --- a/stratosphere/boot/source/boot_battery_driver.hpp +++ b/stratosphere/boot/source/boot_battery_driver.hpp @@ -14,45 +14,60 @@ * along with this program. If not, see . */ #pragma once +#include namespace ams::boot { class BatteryDriver { private: - i2c::driver::I2cSession i2c_session; + powctl::Session battery_session; public: - BatteryDriver() { - R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max17050)); + BatteryDriver() : battery_session() { + R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->battery_session), powctl::DeviceCode_Max17050, ddsf::AccessMode_ReadWrite)); } ~BatteryDriver() { - i2c::driver::CloseSession(this->i2c_session); + powctl::CloseSession(this->battery_session); } - private: - 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); + Result IsBatteryRemoved(bool *out) { + bool present; + R_TRY(powctl::IsBatteryPresent(std::addressof(present), this->battery_session)); + + return present == false; + } + + Result GetSocRep(float *out) { + return powctl::GetBatterySocRep(out, this->battery_session); + } + + Result GetAverageVCell(int *out) { + return powctl::GetBatteryAverageVCell(out, this->battery_session); + } + + Result GetOpenCircuitVoltage(int *out) { + return powctl::GetBatteryOpenCircuitVoltage(out, this->battery_session); + } + + Result GetAverageCurrent(int *out) { + return powctl::GetBatteryAverageCurrent(out, this->battery_session); + } + + Result GetCurrent(int *out) { + return powctl::GetBatteryCurrent(out, this->battery_session); + } + + Result GetTemperature(float *out) { + return powctl::GetBatteryTemperature(out, this->battery_session); + } + + Result IsI2cShutdownEnabled(bool *out) { + return powctl::IsBatteryI2cShutdownEnabled(out, this->battery_session); + } + + Result SetI2cShutdownEnabled(bool en) { + return powctl::SetBatteryI2cShutdownEnabled(this->battery_session, en); + } }; } diff --git a/stratosphere/boot/source/boot_battery_icons.cpp b/stratosphere/boot/source/boot_battery_icons.cpp index af7b0e425..f580d0f35 100644 --- a/stratosphere/boot/source/boot_battery_icons.cpp +++ b/stratosphere/boot/source/boot_battery_icons.cpp @@ -22,9 +22,9 @@ namespace ams::boot { namespace { /* Pull in icon definitions. */ -#include "boot_battery_icon_low.inc" -#include "boot_battery_icon_charging.inc" -#include "boot_battery_icon_charging_red.inc" + #include "boot_battery_icon_low.inc" + #include "boot_battery_icon_charging.inc" + #include "boot_battery_icon_charging_red.inc" /* Helpers. */ 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) { @@ -54,12 +54,12 @@ namespace ams::boot { { /* Low battery icon is shown for 5 seconds. */ ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery); - svcSleepThread(5'000'000'000ul); + os::SleepThread(TimeSpan::FromSeconds(5)); } FinalizeDisplay(); } - void StartShowChargingIcon(size_t battery_percentage, bool wait) { + void StartShowChargingIcon(int battery_percentage, bool wait) { const bool is_red = battery_percentage <= 15; const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX; @@ -70,7 +70,7 @@ namespace ams::boot { 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(IconMeterW * (1.0 - (0.0404 + 0.0096 * battery_percentage)) + 0.5); + const size_t MeterFillW = static_cast(IconMeterW * (1.0 - (0.0404 + 0.0096 * static_cast(battery_percentage))) + 0.5); /* Create stack buffer, copy icon into it, draw fill meter, draw. */ { @@ -84,7 +84,7 @@ namespace ams::boot { /* Wait for 2 seconds if we're supposed to. */ if (wait) { - svcSleepThread(2'000'000'000ul); + os::SleepThread(TimeSpan::FromSeconds(2)); } } diff --git a/stratosphere/boot/source/boot_battery_icons.hpp b/stratosphere/boot/source/boot_battery_icons.hpp index 8cd180fff..ee8b0bcf0 100644 --- a/stratosphere/boot/source/boot_battery_icons.hpp +++ b/stratosphere/boot/source/boot_battery_icons.hpp @@ -15,12 +15,21 @@ */ #pragma once #include +#include "boot_display.hpp" namespace ams::boot { /* Battery Display utilities. */ void ShowLowBatteryIcon(); - void StartShowChargingIcon(size_t battery_percentage, bool wait); + void StartShowChargingIcon(int battery_percentage, bool wait); void EndShowChargingIcon(); + inline void StartShowChargingIcon(int battery_percentage) { + return StartShowChargingIcon(battery_percentage, true); + } + + inline void StartShowLowBatteryChargingIcon() { + return StartShowChargingIcon(1, false); + } + } diff --git a/stratosphere/boot/source/boot_battery_parameters.inc b/stratosphere/boot/source/boot_battery_parameters.inc deleted file mode 100644 index fd7ca3586..000000000 --- a/stratosphere/boot/source/boot_battery_parameters.inc +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2018-2020 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 . - */ - -constexpr u8 Max17050Status = 0x00; -constexpr u8 Max17050VAlrtThreshold = 0x01; -constexpr u8 Max17050TAlrtThreshold = 0x02; -constexpr u8 Max17050SocAlrtThreshold = 0x03; -constexpr u8 Max17050AtRate = 0x04; -constexpr u8 Max17050RemCapRep = 0x05; -constexpr u8 Max17050SocRep = 0x06; -constexpr u8 Max17050Age = 0x07; -constexpr u8 Max17050Temperature = 0x08; -constexpr u8 Max17050VCell = 0x09; -constexpr u8 Max17050Current = 0x0A; -constexpr u8 Max17050AverageCurrent = 0x0B; - -constexpr u8 Max17050SocMix = 0x0D; -constexpr u8 Max17050SocAv = 0x0E; -constexpr u8 Max17050RemCapMix = 0x0F; -constexpr u8 Max17050FullCap = 0x10; -constexpr u8 Max17050Tte = 0x11; -constexpr u8 Max17050QResidual00 = 0x12; -constexpr u8 Max17050FullSocThr = 0x13; - - -constexpr u8 Max17050AverageTemp = 0x16; -constexpr u8 Max17050Cycles = 0x17; -constexpr u8 Max17050DesignCap = 0x18; -constexpr u8 Max17050AverageVCell = 0x19; -constexpr u8 Max17050MaxMinTemp = 0x1A; -constexpr u8 Max17050MaxMinVoltage = 0x1B; -constexpr u8 Max17050MaxMinCurrent = 0x1C; -constexpr u8 Max17050Config = 0x1D; -constexpr u8 Max17050IChgTerm = 0x1E; -constexpr u8 Max17050RemCapAv = 0x1F; - -constexpr u8 Max17050Version = 0x21; -constexpr u8 Max17050QResidual10 = 0x22; -constexpr u8 Max17050FullCapNom = 0x23; -constexpr u8 Max17050TempNom = 0x24; -constexpr u8 Max17050TempLim = 0x25; - -constexpr u8 Max17050Ain = 0x27; -constexpr u8 Max17050LearnCfg = 0x28; -constexpr u8 Max17050FilterCfg = 0x29; -constexpr u8 Max17050RelaxCfg = 0x2A; -constexpr u8 Max17050MiscCfg = 0x2B; -constexpr u8 Max17050TGain = 0x2C; -constexpr u8 Max17050TOff = 0x2D; -constexpr u8 Max17050CGain = 0x2E; -constexpr u8 Max17050COff = 0x2F; - - -constexpr u8 Max17050QResidual20 = 0x32; - - - -constexpr u8 Max17050IAvgEmpty = 0x36; -constexpr u8 Max17050FCtc = 0x37; -constexpr u8 Max17050RComp0 = 0x38; -constexpr u8 Max17050TempCo = 0x39; -constexpr u8 Max17050VEmpty = 0x3A; - - -constexpr u8 Max17050FStat = 0x3D; -constexpr u8 Max17050Timer = 0x3E; -constexpr u8 Max17050ShdnTimer = 0x3F; - - -constexpr u8 Max17050QResidual30 = 0x42; - - -constexpr u8 Max17050DQAcc = 0x45; -constexpr u8 Max17050DPAcc = 0x46; - -constexpr u8 Max17050SocVf0 = 0x48; - -constexpr u8 Max17050Qh0 = 0x4C; -constexpr u8 Max17050Qh = 0x4D; - -constexpr u8 Max17050SocVfAccess = 0x60; - -constexpr u8 Max17050ModelAccess0 = 0x62; -constexpr u8 Max17050ModelAccess1 = 0x63; - -constexpr u8 Max17050ModelChrTblStart = 0x80; -constexpr u8 Max17050ModelChrTblEnd = 0xB0; - - -constexpr u8 Max17050VFocV = 0xFB; -constexpr u8 Max17050SocVf = 0xFF; - -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!"); - -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 */ -}; - -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 */ -}; - -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 */ -}; - -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 */ -}; - -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 */ -}; - -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 */ -}; diff --git a/stratosphere/boot/source/boot_boot_reason.cpp b/stratosphere/boot/source/boot_boot_reason.cpp index 0c255434f..f6de42059 100644 --- a/stratosphere/boot/source/boot_boot_reason.cpp +++ b/stratosphere/boot/source/boot_boot_reason.cpp @@ -23,29 +23,29 @@ namespace ams::boot { namespace { /* Globals. */ - u32 g_boot_reason = 0; - bool g_detected_boot_reason = false; + constinit spl::BootReason g_boot_reason = spl::BootReason_Unknown; + constinit bool g_detected_boot_reason = false; /* Helpers. */ - u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) { + spl::BootReason DetectBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) { if (power_intr & 0x08) { - return 2; + return spl::BootReason_OnKey; } if (rtc_intr & 0x02) { - return 3; + return spl::BootReason_RtcAlarm1; } if (power_intr & 0x80) { - return 1; + return spl::BootReason_AcOk; } if (rtc_intr & 0x04) { if (nv_erc != 0x80 && !spl::IsRecoveryBoot()) { - return 4; + return spl::BootReason_RtcAlarm2; } } if ((nv_erc & 0x40) && ac_ok) { - return 1; + return spl::BootReason_AcOk; } - return 0; + return spl::BootReason_Unknown; } } @@ -60,37 +60,38 @@ namespace ams::boot { /* Get values from PMIC. */ { PmicDriver pmic_driver; - R_ABORT_UNLESS(pmic_driver.GetPowerIntr(&power_intr)); - R_ABORT_UNLESS(pmic_driver.GetNvErc(&nv_erc)); - R_ABORT_UNLESS(pmic_driver.GetAcOk(&ac_ok)); + R_ABORT_UNLESS(pmic_driver.GetOnOffIrq(std::addressof(power_intr))); + R_ABORT_UNLESS(pmic_driver.GetNvErc(std::addressof(nv_erc))); + R_ABORT_UNLESS(pmic_driver.GetAcOk(std::addressof(ac_ok))); } /* Get values from RTC. */ { RtcDriver rtc_driver; - R_ABORT_UNLESS(rtc_driver.GetRtcIntr(&rtc_intr)); - R_ABORT_UNLESS(rtc_driver.GetRtcIntrM(&rtc_intr_m)); + R_ABORT_UNLESS(rtc_driver.GetRtcIntr(std::addressof(rtc_intr))); + R_ABORT_UNLESS(rtc_driver.GetRtcIntrM(std::addressof(rtc_intr_m))); } /* Set global derived boot reason. */ - g_boot_reason = MakeBootReason(power_intr, rtc_intr & ~rtc_intr_m, nv_erc, ac_ok); + g_boot_reason = DetectBootReason(power_intr, rtc_intr & ~rtc_intr_m, nv_erc, ac_ok); /* Set boot reason for SPL. */ if (hos::GetVersion() >= hos::Version_3_0_0) { + /* Create the boot reason value. */ 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; + /* Set the boot reason value. */ R_ABORT_UNLESS(spl::SetBootReason(boot_reason_value)); } g_detected_boot_reason = true; } - u32 GetBootReason() { + spl::BootReason GetBootReason() { AMS_ABORT_UNLESS(g_detected_boot_reason); return g_boot_reason; } diff --git a/stratosphere/boot/source/boot_boot_reason.hpp b/stratosphere/boot/source/boot_boot_reason.hpp index f2f307ddb..6f39648b6 100644 --- a/stratosphere/boot/source/boot_boot_reason.hpp +++ b/stratosphere/boot/source/boot_boot_reason.hpp @@ -20,6 +20,6 @@ namespace ams::boot { /* Boot Reason utilities. */ void DetectBootReason(); - u32 GetBootReason(); + spl::BootReason GetBootReason(); } diff --git a/stratosphere/boot/source/boot_bq24193_charger.hpp b/stratosphere/boot/source/boot_bq24193_charger.hpp deleted file mode 100644 index 7a59b3f99..000000000 --- a/stratosphere/boot/source/boot_bq24193_charger.hpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2018-2020 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 . - */ -#pragma once -#include - -namespace ams::boot::bq24193 { - - constexpr u8 InputSourceControl = 0x00; - constexpr u8 PowerOnConfiguration = 0x01; - constexpr u8 ChargeCurrentControl = 0x02; - constexpr u8 PreChargeTerminationCurrentControl = 0x03; - constexpr u8 ChargeVoltageControl = 0x04; - constexpr u8 ChargeTerminationTimerControl = 0x05; - constexpr u8 IrCompensationThermalRegulationControl = 0x06; - constexpr u8 MiscOperationControl = 0x07; - constexpr u8 SystemStatus = 0x08; - constexpr u8 Fault = 0x09; - constexpr u8 VendorPartRevisionStatus = 0x0A; - - enum ChargerConfiguration : u8 { - ChargerConfiguration_ChargeDisable = (0 << 4), - ChargerConfiguration_ChargeBattery = (1 << 4), - ChargerConfiguration_Otg = (2 << 4), - }; - - constexpr u32 ChargeVoltageLimitMin = 3504; - constexpr u32 ChargeVoltageLimitMax = 4208; - - inline u8 EncodeChargeVoltageLimit(u32 voltage) { - AMS_ABORT_UNLESS(voltage >= ChargeVoltageLimitMin); - AMS_ABORT_UNLESS(voltage <= ChargeVoltageLimitMax); - - voltage -= ChargeVoltageLimitMin; - voltage >>= 4; - return static_cast(voltage << 2); - } - - inline u32 DecodeChargeVoltageLimit(u8 reg) { - return ChargeVoltageLimitMin + (static_cast(reg & 0xFC) << 2); - } - - constexpr u32 FastChargeCurrentLimitMin = 512; - constexpr u32 FastChargeCurrentLimitMax = 4544; - - inline u8 EncodeFastChargeCurrentLimit(u32 current) { - AMS_ABORT_UNLESS(current >= FastChargeCurrentLimitMin); - AMS_ABORT_UNLESS(current <= FastChargeCurrentLimitMax); - - current -= FastChargeCurrentLimitMin; - current >>= 6; - return static_cast(current << 2); - } - - inline u32 DecodeFastChargeCurrentLimit(u8 reg) { - return FastChargeCurrentLimitMin + (static_cast(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, - }; - - constexpr u32 PreChargeCurrentLimitMin = 128; - constexpr u32 PreChargeCurrentLimitMax = 2048; - - inline u8 EncodePreChargeCurrentLimit(u32 current) { - AMS_ABORT_UNLESS(current >= PreChargeCurrentLimitMin); - AMS_ABORT_UNLESS(current <= PreChargeCurrentLimitMax); - - current -= PreChargeCurrentLimitMin; - current >>= 7; - return static_cast(current << 4); - } - - inline u32 DecodePreChargeCurrentLimit(u8 reg) { - return PreChargeCurrentLimitMin + (static_cast(reg & 0xF0) << 3); - } - - constexpr u32 TerminationCurrentLimitMin = 128; - constexpr u32 TerminationCurrentLimitMax = 2048; - - inline u8 EncodeTerminationCurrentLimit(u32 current) { - AMS_ABORT_UNLESS(current >= TerminationCurrentLimitMin); - AMS_ABORT_UNLESS(current <= TerminationCurrentLimitMax); - - current -= TerminationCurrentLimitMin; - current >>= 7; - return static_cast(current); - } - - inline u32 DecodeTerminationCurrentLimit(u8 reg) { - return TerminationCurrentLimitMin + (static_cast(reg & 0xF) << 7); - } - - constexpr u32 MinimumSystemVoltageLimitMin = 3000; - constexpr u32 MinimumSystemVoltageLimitMax = 3700; - - inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) { - AMS_ABORT_UNLESS(voltage >= MinimumSystemVoltageLimitMin); - AMS_ABORT_UNLESS(voltage <= MinimumSystemVoltageLimitMax); - - voltage -= MinimumSystemVoltageLimitMin; - voltage /= 100; - return static_cast(voltage << 1); - } - - inline u32 DecodeMinimumSystemVoltageLimit(u8 reg) { - return MinimumSystemVoltageLimitMin + (static_cast(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, - }; - -} diff --git a/stratosphere/boot/source/boot_calibration.cpp b/stratosphere/boot/source/boot_calibration.cpp deleted file mode 100644 index 6257609f3..000000000 --- a/stratosphere/boot/source/boot_calibration.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include "boot_calibration.hpp" - -namespace ams::boot { - - namespace { - - /* Convenience definitions. */ - constexpr size_t BatteryLotOffset = 0x2CE0; - constexpr size_t BatteryLotSize = 0x20; - constexpr size_t BatteryVersionOffset = 0x4310; - constexpr size_t BatteryVersionSize = 0x10; - - constexpr u32 DefaultBatteryVendor = static_cast('A'); - constexpr u32 DefaultBatteryVersion = 0; - - /* Helpers. */ - constexpr u16 GetCrc16(const void *data, size_t size) { - constexpr u16 s_crc_table[0x10] = { - 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, - 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 - }; - - AMS_ABORT_UNLESS(data != nullptr); - - u16 crc16 = 0x55AA; - const u8 *data_u8 = reinterpret_cast(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; - } - - Result ValidateCalibrationCrc16(const void *data, size_t size) { - const u8 *data_u8 = reinterpret_cast(data); - const bool crc_valid = GetCrc16(data, size - sizeof(u16)) == *(reinterpret_cast(&data_u8[size - sizeof(u16)])); - R_UNLESS(crc_valid, cal::ResultCalibrationDataCrcError()); - return ResultSuccess(); - } - - Result GetBatteryVendorImpl(u32 *vendor) { - FsStorage s; - R_TRY(fsOpenBisStorage(&s, FsBisPartitionId_CalibrationBinary)); - ON_SCOPE_EXIT { fsStorageClose(&s); }; - - u8 battery_lot[BatteryLotSize]; - R_TRY(fsStorageRead(&s, BatteryLotOffset, battery_lot, sizeof(battery_lot))); - - R_TRY(ValidateCalibrationCrc16(battery_lot, sizeof(battery_lot))); - - *vendor = battery_lot[7]; - return ResultSuccess(); - } - - Result GetBatteryVersionImpl(u32 *version) { - FsStorage s; - R_TRY(fsOpenBisStorage(&s, FsBisPartitionId_CalibrationBinary)); - ON_SCOPE_EXIT { fsStorageClose(&s); }; - - u8 battery_version[BatteryVersionSize]; - R_TRY(fsStorageRead(&s, BatteryVersionOffset, battery_version, sizeof(battery_version))); - - R_TRY(ValidateCalibrationCrc16(battery_version, sizeof(battery_version))); - - *version = battery_version[0]; - return ResultSuccess(); - } - - } - - u32 GetBatteryVendor() { - u32 vendor; - if (R_FAILED(GetBatteryVendorImpl(&vendor))) { - return DefaultBatteryVendor; - } - return vendor; - } - - u32 GetBatteryVersion() { - u32 version; - if (R_FAILED(GetBatteryVersionImpl(&version))) { - return DefaultBatteryVersion; - } - return version; - } - -} diff --git a/stratosphere/boot/source/boot_change_voltage.cpp b/stratosphere/boot/source/boot_change_voltage.cpp index b73f38b8f..b5d53166d 100644 --- a/stratosphere/boot/source/boot_change_voltage.cpp +++ b/stratosphere/boot/source/boot_change_voltage.cpp @@ -15,7 +15,6 @@ */ #include #include "boot_change_voltage.hpp" -#include "boot_pmc_wrapper.hpp" namespace ams::boot { @@ -36,8 +35,8 @@ namespace ams::boot { void ChangeGpioVoltageTo1_8v() { /* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */ - WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask); - WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask); + dd::ReadModifyWriteIoRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask); + dd::ReadModifyWriteIoRegister(PmcPwrDetVal, 0, VoltageChangeMask); /* Sleep for 100 us. */ svcSleepThread(100'000ul); diff --git a/stratosphere/boot/source/boot_charger_driver.cpp b/stratosphere/boot/source/boot_charger_driver.cpp deleted file mode 100644 index be8015818..000000000 --- a/stratosphere/boot/source/boot_charger_driver.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include "boot_charger_driver.hpp" - -namespace ams::boot { - - Result ChargerDriver::Read(u8 addr, u8 *out) { - return ReadI2cRegister(this->i2c_session, reinterpret_cast(out), sizeof(*out), &addr, sizeof(addr)); - } - - Result ChargerDriver::Write(u8 addr, u8 val) { - return WriteI2cRegister(this->i2c_session, reinterpret_cast(&val), sizeof(val), &addr, sizeof(addr)); - } - - Result ChargerDriver::ReadWrite(u8 addr, u8 mask, u8 val) { - u8 cur_val; - R_TRY(this->Read(addr, &cur_val)); - - const u8 new_val = (cur_val & ~mask) | val; - R_TRY(this->Write(addr, new_val)); - return ResultSuccess(); - } - - Result ChargerDriver::Initialize() { - return this->Initialize(true); - } - - Result ChargerDriver::Initialize(bool set_input_current_limit) { - if (set_input_current_limit) { - R_TRY(this->SetInputCurrentLimit(bq24193::InputCurrentLimit_500mA)); - } - - R_TRY(this->SetChargeVoltageLimit(4208)); - R_TRY(this->SetFastChargeCurrentLimit(512)); - R_TRY(this->SetForce20PercentChargeCurrent(false)); - R_TRY(this->SetPreChargeCurrentLimit(128)); - R_TRY(this->SetTerminationCurrentLimit(128)); - R_TRY(this->SetMinimumSystemVoltageLimit(3000)); - R_TRY(this->SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting_Disabled)); - R_TRY(this->SetChargingSafetyTimerEnabled(false)); - R_TRY(this->ResetWatchdogTimer()); - R_TRY(this->SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit_500mA)); - R_TRY(this->SetHiZEnabled(false)); - - return ResultSuccess(); - } - - Result ChargerDriver::SetChargeEnabled(bool enabled) { - /* TODO */ - AMS_ABORT(); - /* boot::gpio::SetValue(GpioPadName_Bq24193Charger, enabled ? GpioValue_Low : GpioValue_High); */ - return this->SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeBattery); - } - - Result ChargerDriver::SetChargerConfiguration(bq24193::ChargerConfiguration config) { - return this->ReadWrite(bq24193::PowerOnConfiguration, 0x30, config); - } - - Result ChargerDriver::SetChargeVoltageLimit(u32 voltage) { - return this->ReadWrite(bq24193::ChargeVoltageControl, 0xFC, bq24193::EncodeChargeVoltageLimit(voltage)); - } - - Result ChargerDriver::SetFastChargeCurrentLimit(u32 current) { - return this->ReadWrite(bq24193::ChargeCurrentControl, 0xFC, bq24193::EncodeFastChargeCurrentLimit(current)); - } - - Result ChargerDriver::SetInputCurrentLimit(bq24193::InputCurrentLimit current) { - return this->ReadWrite(bq24193::InputSourceControl, 0x07, current); - } - - Result ChargerDriver::SetForce20PercentChargeCurrent(bool force) { - return this->ReadWrite(bq24193::ChargeCurrentControl, 0x01, force ? 1 : 0); - } - - Result ChargerDriver::SetPreChargeCurrentLimit(u32 current) { - return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0xF0, bq24193::EncodePreChargeCurrentLimit(current)); - } - - Result ChargerDriver::SetTerminationCurrentLimit(u32 current) { - return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0x0F, bq24193::EncodeTerminationCurrentLimit(current)); - } - - Result ChargerDriver::SetMinimumSystemVoltageLimit(u32 voltage) { - return this->ReadWrite(bq24193::PowerOnConfiguration, 0x0E, bq24193::EncodeMinimumSystemVoltageLimit(voltage)); - } - - Result ChargerDriver::SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting) { - return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x30, setting); - } - - Result ChargerDriver::SetChargingSafetyTimerEnabled(bool enabled) { - return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x08, enabled ? 0x08 : 0); - } - - Result ChargerDriver::ResetWatchdogTimer() { - return this->ReadWrite(bq24193::PowerOnConfiguration, 0x40, 0x40); - } - - Result ChargerDriver::SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current) { - return this->ReadWrite(bq24193::PowerOnConfiguration, 0x01, current); - } - - Result ChargerDriver::SetHiZEnabled(bool enabled) { - return this->ReadWrite(bq24193::InputSourceControl, 0x80, enabled ? 0x80 : 0); - } - - Result ChargerDriver::GetInputCurrentLimit(bq24193::InputCurrentLimit *out) { - u8 limit; - R_TRY(this->Read(bq24193::InputSourceControl, &limit)); - *out = static_cast(limit); - return ResultSuccess(); - } - - Result ChargerDriver::GetChargeVoltageLimit(u32 *out) { - u8 reg; - R_TRY(this->Read(bq24193::ChargeVoltageControl, ®)); - *out = bq24193::DecodeChargeVoltageLimit(reg); - return ResultSuccess(); - } - -} \ No newline at end of file diff --git a/stratosphere/boot/source/boot_charger_driver.hpp b/stratosphere/boot/source/boot_charger_driver.hpp index a1fa357e4..40c2c65ca 100644 --- a/stratosphere/boot/source/boot_charger_driver.hpp +++ b/stratosphere/boot/source/boot_charger_driver.hpp @@ -14,52 +14,111 @@ * along with this program. If not, see . */ #pragma once -#include "boot_bq24193_charger.hpp" -#include "boot_i2c_utils.hpp" +#include namespace ams::boot { + enum ChargerStatus { + ChargerStatus_Unknown = 0, + ChargerStatus_Charging = 1, + ChargerStatus_NotCharging = 2, + ChargerStatus_ChargeTerminationDone = 3, + }; + class ChargerDriver { private: - static constexpr u32 GpioPadName_Bq24193Charger = 0xA; - private: - i2c::driver::I2cSession i2c_session; + powctl::Session charger_session; public: - ChargerDriver() { - R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Bq24193)); - - //boot::gpio::Configure(GpioPadName_Bq24193Charger); - //boot::gpio::SetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output); + ChargerDriver() : charger_session() { + R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->charger_session), powctl::DeviceCode_Bq24193, ddsf::AccessMode_ReadWrite)); } ~ChargerDriver() { - i2c::driver::CloseSession(this->i2c_session); + powctl::CloseSession(this->charger_session); } - private: - Result Read(u8 addr, u8 *out_data); - Result Write(u8 addr, u8 val); - Result ReadWrite(u8 addr, u8 mask, u8 val); - Result SetInputCurrentLimit(bq24193::InputCurrentLimit current); - Result SetForce20PercentChargeCurrent(bool force); - Result SetPreChargeCurrentLimit(u32 current); - Result SetTerminationCurrentLimit(u32 current); - Result SetMinimumSystemVoltageLimit(u32 voltage); - Result SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting); - Result SetChargingSafetyTimerEnabled(bool enabled); - Result ResetWatchdogTimer(); - Result SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current); - Result SetHiZEnabled(bool enabled); + Result Initialize(bool set_input_current_limit) { + /* Set input current limit to 500 ma. */ + if (set_input_current_limit) { + R_TRY(powctl::SetChargerInputCurrentLimit(this->charger_session, 500)); + } - public: - Result Initialize(); - Result Initialize(bool set_input_current_limit); - Result SetChargeVoltageLimit(u32 voltage); - Result SetFastChargeCurrentLimit(u32 current); - Result SetChargeEnabled(bool enabled); - Result SetChargerConfiguration(bq24193::ChargerConfiguration config); - Result GetInputCurrentLimit(bq24193::InputCurrentLimit *out); - Result GetChargeVoltageLimit(u32 *out); + /* Set input voltage limit to 500 mv. */ + R_TRY(powctl::SetChargerInputVoltageLimit(this->charger_session, 500)); + + /* Disable hi-z mode. */ + R_TRY(powctl::SetChargerHiZEnabled(this->charger_session, false)); + + /* Set configuration to charge battery. */ + R_TRY(powctl::SetChargerChargerConfiguration(this->charger_session, powctl::ChargerConfiguration_ChargeBattery)); + + return ResultSuccess(); + } + + Result GetChargeCurrentState(powctl::ChargeCurrentState *out) { + return powctl::GetChargerChargeCurrentState(out, this->charger_session); + } + + Result SetChargeCurrentState(powctl::ChargeCurrentState state) { + return powctl::SetChargerChargeCurrentState(this->charger_session, state); + } + + Result GetInputCurrentLimit(int *out) { + return powctl::GetChargerInputCurrentLimit(out, this->charger_session); + } + + Result SetChargerConfiguration(powctl::ChargerConfiguration cfg) { + return powctl::SetChargerChargerConfiguration(this->charger_session, cfg); + } + + Result GetFastChargeCurrentLimit(int *out) { + return powctl::GetChargerFastChargeCurrentLimit(out, this->charger_session); + } + + Result SetFastChargeCurrentLimit(int limit) { + return powctl::SetChargerFastChargeCurrentLimit(this->charger_session, limit); + } + + Result GetChargeVoltageLimit(int *out) { + return powctl::GetChargerChargeVoltageLimit(out, this->charger_session); + } + + Result SetChargeVoltageLimit(int limit) { + return powctl::SetChargerChargeVoltageLimit(this->charger_session, limit); + } + + Result GetChargerStatus(boot::ChargerStatus *out) { + /* Default to unknown. */ + *out = ChargerStatus_Unknown; + + /* Get the powctl status. */ + powctl::ChargerStatus powctl_status; + R_TRY(powctl::GetChargerChargerStatus(std::addressof(powctl_status), this->charger_session)); + + switch (powctl_status) { + case powctl::ChargerStatus_Charging: *out = boot::ChargerStatus_Charging; break; + case powctl::ChargerStatus_NotCharging: *out = boot::ChargerStatus_NotCharging; break; + case powctl::ChargerStatus_ChargeTerminationDone: *out = boot::ChargerStatus_ChargeTerminationDone; break; + } + + return ResultSuccess(); + } + + Result GetBatteryCompensation(int *out) { + return powctl::GetChargerBatteryCompensation(out, this->charger_session); + } + + Result SetBatteryCompensation(int v) { + return powctl::SetChargerBatteryCompensation(this->charger_session, v); + } + + Result GetVoltageClamp(int *out) { + return powctl::GetChargerVoltageClamp(out, this->charger_session); + } + + Result SetVoltageClamp(int v) { + return powctl::SetChargerVoltageClamp(this->charger_session, v); + } }; } diff --git a/stratosphere/boot/source/boot_check_battery.cpp b/stratosphere/boot/source/boot_check_battery.cpp index 63b6627e4..3be3c88fb 100644 --- a/stratosphere/boot/source/boot_check_battery.cpp +++ b/stratosphere/boot/source/boot_check_battery.cpp @@ -14,19 +14,25 @@ * along with this program. If not, see . */ #include -#include "boot_battery_driver.hpp" +#include "boot_check_battery.hpp" #include "boot_battery_icons.hpp" #include "boot_boot_reason.hpp" -#include "boot_calibration.hpp" -#include "boot_charger_driver.hpp" -#include "boot_check_battery.hpp" #include "boot_pmic_driver.hpp" +#include "boot_battery_driver.hpp" +#include "boot_charger_driver.hpp" #include "boot_power_utils.hpp" namespace ams::boot { namespace { + /* Value definitions. */ + constexpr inline double BatteryLevelThresholdForBoot = 3.0; + constexpr inline double BatteryLevelThresholdForFullCharge = 99.0; + + constexpr inline int BatteryVoltageThresholdConnected = 4000; + constexpr inline int BatteryVoltageThresholdDisconnected = 3650; + /* Types. */ enum class CheckBatteryResult { Success, @@ -34,251 +40,488 @@ namespace ams::boot { Reboot, }; - 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; + class BatteryChecker { + private: + boot::ChargerDriver &charger_driver; + boot::BatteryDriver &battery_driver; + const powctl::driver::impl::ChargeParameters &charge_parameters; + powctl::driver::impl::ChargeArbiter charge_arbiter; + powctl::ChargeCurrentState charge_current_state; + int fast_charge_current_limit; + int charge_voltage_limit; + int battery_compensation; + int voltage_clamp; + TimeSpan charging_done_interval; + bool has_start_time; + TimeSpan start_time; + private: + bool IsChargeDone(); + void UpdateChargeDoneCurrent(); + void ApplyArbiterRule(); + void PrintBatteryStatus(float raw_charge, int voltage, int voltage_threshold); + CheckBatteryResult LoopCheckBattery(bool reboot_on_power_button_press, bool return_on_enough_battery, bool shutdown_on_full_battery, bool show_display, bool show_charging_display); + + void UpdateStartTime() { + /* Update start time. */ + this->start_time = os::ConvertToTimeSpan(os::GetSystemTick()); + this->has_start_time = true; + } + public: + BatteryChecker(boot::ChargerDriver &cd, boot::BatteryDriver &bd, const powctl::driver::impl::ChargeParameters &cp, int cvl) : charger_driver(cd), battery_driver(bd), charge_parameters(cp), charge_arbiter(cp.rules, cp.num_rules, cvl), charging_done_interval(TimeSpan::FromSeconds(2)), has_start_time(false) { + /* Get parameters from charger. */ + if (R_FAILED(this->charger_driver.GetChargeCurrentState(std::addressof(this->charge_current_state)))) { + boot::ShutdownSystem(); + } + if (R_FAILED(this->charger_driver.GetFastChargeCurrentLimit(std::addressof(this->fast_charge_current_limit)))) { + boot::ShutdownSystem(); + } + if (R_FAILED(this->charger_driver.GetChargeVoltageLimit(std::addressof(this->charge_voltage_limit)))) { + boot::ShutdownSystem(); + } + if (R_FAILED(this->charger_driver.GetBatteryCompensation(std::addressof(this->battery_compensation)))) { + boot::ShutdownSystem(); + } + if (R_FAILED(this->charger_driver.GetVoltageClamp(std::addressof(this->voltage_clamp)))) { + boot::ShutdownSystem(); + } + + /* Update start time. */ + this->UpdateStartTime(); + } + + CheckBatteryResult LoopCheckBattery(spl::BootReason boot_reason) { + if (boot_reason == spl::BootReason_RtcAlarm2) { + /* RTC Alarm 2 boot (QuasiOff) */ + return this->LoopCheckBattery(true, false, true, false, false); + } else if (boot_reason == spl::BootReason_AcOk) { + /* ACOK boot */ + return this->LoopCheckBattery(true, true, false, true, true); + } else { + /* Normal boot */ + return this->LoopCheckBattery(false, true, false, true, false); + } + } + + void UpdateCharger(); }; - /* Battery parameters. */ - 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, - }; + void BatteryChecker::PrintBatteryStatus(float raw_charge, int voltage, int voltage_threshold) { + /* TODO: Print charge/voltage/threshold. */ + AMS_UNUSED(raw_charge, voltage, voltage_threshold); - 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, - }; - - 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, - }; - - constexpr const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_version) { - switch (battery_version) { - case 0: - return &BatteryChargeParameters0; - case 1: - return &BatteryChargeParameters1; - case 2: - return &BatteryChargeParameters2; - AMS_UNREACHABLE_DEFAULT_CASE(); + /* Get various battery metrics. */ + int avg_current, current, open_circuit_voltage; + float temp; + if (R_FAILED(this->battery_driver.GetAverageCurrent(std::addressof(avg_current)))) { + return; } + if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(current)))) { + return; + } + if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) { + return; + } + if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(open_circuit_voltage)))) { + return; + } + + /* TODO: Print the things we just got. */ + AMS_UNUSED(avg_current, current, temp, open_circuit_voltage); } - /* Helpers. */ - 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 BatteryChecker::IsChargeDone() { + /* Get the charger status. */ + boot::ChargerStatus charger_status; + if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) { + boot::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; + /* If charge status isn't done, we're not done. */ + if (charger_status != boot::ChargerStatus_ChargeTerminationDone) { + return false; + } + + /* Return whether a done current of zero is acceptable. */ + return this->charge_arbiter.IsBatteryDoneCurrentAcceptable(0); + } + + void BatteryChecker::UpdateChargeDoneCurrent() { + int done_current = 0; + if (this->has_start_time && (os::ConvertToTimeSpan(os::GetSystemTick()) - this->start_time) >= this->charging_done_interval) { + /* Get the current. */ + if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(done_current)))) { + boot::ShutdownSystem(); } - } 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); + } else { + /* Get the charger status. */ + boot::ChargerStatus charger_status; + if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) { + boot::ShutdownSystem(); + } + + /* If the charger status isn't done, don't update. */ + if (charger_status != boot::ChargerStatus_ChargeTerminationDone) { + return; } } - 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); + /* Update done current. */ + this->charge_arbiter.SetBatteryDoneCurrent(done_current); + } + + void BatteryChecker::UpdateCharger() { + /* Get the battery temperature. */ + float temp; + if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) { + boot::ShutdownSystem(); } - if (R_FAILED(charger_driver->SetChargeEnabled(enable_charge))) { - pmic_driver->ShutdownSystem(); + /* Update the temperature level. */ + powctl::BatteryTemperatureLevel temp_level; + if (temp < static_cast(this->charge_parameters.temp_min)) { + temp_level = powctl::BatteryTemperatureLevel::TooLow; + } else if (temp < static_cast(this->charge_parameters.temp_low)) { + temp_level = powctl::BatteryTemperatureLevel::Low; + } else if (temp < static_cast(this->charge_parameters.temp_high)) { + temp_level = powctl::BatteryTemperatureLevel::Medium; + } else if (temp < static_cast(this->charge_parameters.temp_max)) { + temp_level = powctl::BatteryTemperatureLevel::High; + } else { + temp_level = powctl::BatteryTemperatureLevel::TooHigh; } - if (R_FAILED(charger_driver->SetChargeVoltageLimit(charge_voltage_limit))) { - pmic_driver->ShutdownSystem(); + this->charge_arbiter.SetBatteryTemperatureLevel(temp_level); + + /* Update average voltage. */ + int avg_v_cell; + if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(avg_v_cell)))) { + boot::ShutdownSystem(); } - if (R_FAILED(charger_driver->SetFastChargeCurrentLimit(fast_charge_current_limit))) { - pmic_driver->ShutdownSystem(); + this->charge_arbiter.SetBatteryAverageVCell(avg_v_cell); + + /* Update open circuit voltage. */ + int ocv; + if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(ocv)))) { + boot::ShutdownSystem(); + } + this->charge_arbiter.SetBatteryOpenCircuitVoltage(ocv); + + /* Update charge done current. */ + this->UpdateChargeDoneCurrent(); + + /* Update arbiter power state. */ + this->charge_arbiter.SetPowerState(powctl::PowerState::ShutdownChargeMain); + + /* Apply the newly selected rule. */ + this->ApplyArbiterRule(); + } + + void BatteryChecker::ApplyArbiterRule() { + /* Get the selected rule. */ + const auto *rule = this->charge_arbiter.GetSelectedRule(); + AMS_ASSERT(rule != nullptr); + + /* Check if we need to perform charger initialization. */ + const bool reinit_charger = rule->reinitialize_charger; + const auto cur_charge_current_state = this->charge_current_state; + + /* Set the charger to not charging while we make changes. */ + if (!reinit_charger || cur_charge_current_state != powctl::ChargeCurrentState_NotCharging) { + if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_NotCharging))) { + boot::ShutdownSystem(); + } + this->charge_current_state = powctl::ChargeCurrentState_NotCharging; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process fast charge current limit when rule is smaller. */ + const auto rule_fast_charge_current_limit = rule->fast_charge_current_limit; + const auto cur_fast_charge_current_limit = this->fast_charge_current_limit; + if (rule_fast_charge_current_limit < cur_fast_charge_current_limit) { + if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) { + boot::ShutdownSystem(); + } + this->fast_charge_current_limit = rule_fast_charge_current_limit; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process charge voltage limit when rule is smaller. */ + const auto rule_charge_voltage_limit = std::min(rule->charge_voltage_limit, this->charge_arbiter.GetChargeVoltageLimit()); + const auto cur_charge_voltage_limit = this->charge_voltage_limit; + if (rule_charge_voltage_limit < cur_charge_voltage_limit) { + if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) { + boot::ShutdownSystem(); + } + this->charge_voltage_limit = rule_charge_voltage_limit; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process battery compensation when rule is smaller. */ + const auto rule_battery_compensation = rule->battery_compensation; + const auto cur_battery_compensation = this->battery_compensation; + if (rule_battery_compensation < cur_battery_compensation) { + if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) { + boot::ShutdownSystem(); + } + this->battery_compensation = rule_battery_compensation; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process voltage clamp when rule is smaller. */ + const auto rule_voltage_clamp = rule->voltage_clamp; + const auto cur_voltage_clamp = this->voltage_clamp; + if (rule_voltage_clamp < cur_voltage_clamp) { + if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) { + boot::ShutdownSystem(); + } + this->voltage_clamp = rule_voltage_clamp; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process voltage clamp when rule is larger. */ + if (rule_voltage_clamp > cur_voltage_clamp) { + if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) { + boot::ShutdownSystem(); + } + this->voltage_clamp = rule_voltage_clamp; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process battery compensation when rule is larger. */ + if (rule_battery_compensation > cur_battery_compensation) { + if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) { + boot::ShutdownSystem(); + } + this->battery_compensation = rule_battery_compensation; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process fast charge current limit when rule is larger. */ + if (rule_fast_charge_current_limit > cur_fast_charge_current_limit) { + if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) { + boot::ShutdownSystem(); + } + this->fast_charge_current_limit = rule_fast_charge_current_limit; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* Process charge voltage limit when rule is larger. */ + if (rule_charge_voltage_limit > cur_charge_voltage_limit) { + if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) { + boot::ShutdownSystem(); + } + this->charge_voltage_limit = rule_charge_voltage_limit; + + /* Update start time. */ + this->UpdateStartTime(); + } + + /* If we're not charging and we expect to reinitialize the charger, do so. */ + if (cur_charge_current_state != powctl::ChargeCurrentState_Charging && reinit_charger) { + if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_Charging))) { + boot::ShutdownSystem(); + } + this->charge_current_state = powctl::ChargeCurrentState_Charging; + + /* Update start time. */ + this->UpdateStartTime(); } } - 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; - } - - 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) { + CheckBatteryResult BatteryChecker::LoopCheckBattery(bool reboot_on_power_button_press, bool return_on_enough_battery, bool shutdown_on_full_battery, bool show_display, bool show_charging_display) { + /* Ensure that if we show a charging icon, we stop showing it when we're done. */ bool is_showing_charging_icon = false; ON_SCOPE_EXIT { if (is_showing_charging_icon) { - EndShowChargingIcon(); + boot::EndShowChargingIcon(); + is_showing_charging_icon = false; } }; - if (can_show_charging_icon) { - size_t battery_percentage; - if (R_FAILED(battery_driver->GetBatteryPercentage(&battery_percentage))) { + /* Show the charging display, if we should. */ + if (show_charging_display) { + /* Get the raw battery charge. */ + float raw_battery_charge; + if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) { return CheckBatteryResult::Shutdown; } - StartShowChargingIcon(battery_percentage, true); + + /* Display the battery with the appropriate percentage. */ + const auto battery_charge = powctl::impl::ConvertBatteryChargePercentage(raw_battery_charge); + boot::StartShowChargingIcon(battery_charge); is_showing_charging_icon = true; } + /* Loop, checking the battery status. */ + TimeSpan last_progress_time = TimeSpan(0); while (true) { - double battery_charge; - if (R_FAILED(battery_driver->GetSocRep(&battery_charge))) { + /* Get the raw battery charge. */ + float raw_battery_charge; + if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_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? */ - } + /* Get the average vcell. */ + int battery_voltage; + if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(battery_voltage)))) { + return CheckBatteryResult::Shutdown; + } + + /* Get whether we're connected to charger. */ bool ac_ok; - if (R_FAILED(pmic_driver->GetAcOk(&ac_ok))) { + if (R_FAILED((boot::PmicDriver().GetAcOk(std::addressof(ac_ok))))) { return CheckBatteryResult::Shutdown; } - u32 battery_voltage; - if (R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) { - return CheckBatteryResult::Shutdown; - } + /* Decide on a battery voltage threshold. */ + const auto battery_voltage_threshold = ac_ok ? BatteryVoltageThresholdConnected : BatteryVoltageThresholdDisconnected; - 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) { - ShowLowBatteryIcon(); + /* Check if we should return. */ + if (return_on_enough_battery) { + if (raw_battery_charge >= BatteryLevelThresholdForBoot || battery_voltage >= battery_voltage_threshold) { + this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold); + return CheckBatteryResult::Success; } - return CheckBatteryResult::Shutdown; } - if (reboot_on_power_button_pressed) { - bool power_button_pressed; - if (R_FAILED(pmic_driver->GetPowerButtonPressed(&power_button_pressed))) { + /* Otherwise, check if we should shut down. */ + if (shutdown_on_full_battery) { + if (raw_battery_charge >= BatteryLevelThresholdForFullCharge || this->IsChargeDone()) { return CheckBatteryResult::Shutdown; } + } + + /* Perform periodic printing. */ + constexpr TimeSpan PrintProgressInterval = TimeSpan::FromSeconds(10); + const auto cur_time = os::ConvertToTimeSpan(os::GetSystemTick()); + if ((cur_time - last_progress_time) >= PrintProgressInterval) { + last_progress_time = cur_time; + this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold); + } + + /* If we've gotten to this point, we have insufficient battery to boot. If we aren't charging, show low battery and shutdown. */ + if (!ac_ok) { + this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold); + if (show_display && !is_showing_charging_icon) { + boot::ShowLowBatteryIcon(); + } + return CheckBatteryResult::Shutdown; + } + + /* Check if we should reboot due to a power button press. */ + if (reboot_on_power_button_press) { + /* Get the power button value. */ + bool power_button_pressed; + if (R_FAILED((boot::PmicDriver().GetPowerButtonPressed(std::addressof(power_button_pressed))))) { + return CheckBatteryResult::Shutdown; + } + + /* Handle the press (or not). */ if (power_button_pressed) { return CheckBatteryResult::Reboot; } } - if (can_show_battery_icon && !is_showing_charging_icon) { - StartShowChargingIcon(1, false); + /* If we got to this point, we should show the low-battery charging screen. */ + if (show_display && !is_showing_charging_icon) { + boot::StartShowLowBatteryChargingIcon(); is_showing_charging_icon = true; } - svcSleepThread(20'000'000ul); - UpdateCharger(pmic_driver, charger_driver, battery_driver, params, charge_voltage_limit); + /* Wait a bit before checking again. */ + constexpr auto BatteryChargeCheckInterval = TimeSpan::FromMilliSeconds(20); + os::SleepThread(BatteryChargeCheckInterval); + + /* Update the charger. */ + this->UpdateCharger(); } + } + } void CheckBatteryCharge() { - PmicDriver pmic_driver; - BatteryDriver battery_driver; - ChargerDriver charger_driver; + /* Open a sessions for the charger/battery. */ + boot::ChargerDriver charger_driver; + boot::BatteryDriver battery_driver; - if (R_FAILED(battery_driver.InitializeBatteryParameters())) { - pmic_driver.ShutdownSystem(); - } + /* Check if the battery is removed. */ { - bool removed; - if (R_FAILED(battery_driver.IsBatteryRemoved(&removed)) || removed) { - pmic_driver.ShutdownSystem(); + bool removed = false; + if (R_FAILED(battery_driver.IsBatteryRemoved(std::addressof(removed))) || removed) { + boot::ShutdownSystem(); } } - const u32 boot_reason = GetBootReason(); - bq24193::InputCurrentLimit input_current_limit; - if (R_FAILED(charger_driver.Initialize(boot_reason != 4)) || R_FAILED(charger_driver.GetInputCurrentLimit(&input_current_limit))) { - pmic_driver.ShutdownSystem(); - } + /* Get the boot reason. */ + const auto boot_reason = boot::GetBootReason(); - if (input_current_limit <= bq24193::InputCurrentLimit_150mA) { - charger_driver.SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeDisable); - pmic_driver.ShutdownSystem(); - } + /* Initialize the charger driver. */ + if (R_FAILED(charger_driver.Initialize(boot_reason != spl::BootReason_RtcAlarm2))) - const BatteryChargeParameters *params = GetBatteryChargeParameters(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(); + /* Check that the charger input limit is greater than 150 milli-amps. */ + { + int input_current_limit_ma; + if (R_FAILED(charger_driver.GetInputCurrentLimit(std::addressof(input_current_limit_ma)))) { + boot::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); + + if (input_current_limit_ma <= 150) { + charger_driver.SetChargerConfiguration(powctl::ChargerConfiguration_ChargeDisable); + boot::ShutdownSystem(); + } + } + + /* Get the charge parameters. */ + const auto &charge_parameters = powctl::driver::impl::GetChargeParameters(); + + /* Get the charge voltage limit. */ + int charge_voltage_limit_mv; + if (boot_reason != spl::BootReason_RtcAlarm2) { + charge_voltage_limit_mv = charge_parameters.default_charge_voltage_limit; } 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); + if (R_FAILED(charger_driver.GetChargeVoltageLimit(std::addressof(charge_voltage_limit_mv)))) { + boot::ShutdownSystem(); } } - switch (check_result) { + /* Create and update a battery checker. */ + BatteryChecker battery_checker(charger_driver, battery_driver, charge_parameters, charge_voltage_limit_mv); + battery_checker.UpdateCharger(); + + /* Set the display brightness to 25%. */ + boot::SetDisplayBrightness(25); + + /* Check the battery. */ + const CheckBatteryResult check_result = battery_checker.LoopCheckBattery(boot_reason); + + /* Set the display brightness to 100%. */ + boot::SetDisplayBrightness(100); + + /* Handle the check result. */ + switch (check_result) { case CheckBatteryResult::Success: break; case CheckBatteryResult::Shutdown: - pmic_driver.ShutdownSystem(); + boot::ShutdownSystem(); break; case CheckBatteryResult::Reboot: - RebootSystem(); + boot::RebootSystem(); break; AMS_UNREACHABLE_DEFAULT_CASE(); } diff --git a/stratosphere/boot/source/boot_clock_initial_configuration.cpp b/stratosphere/boot/source/boot_clock_initial_configuration.cpp index a87de78aa..6cf267691 100644 --- a/stratosphere/boot/source/boot_clock_initial_configuration.cpp +++ b/stratosphere/boot/source/boot_clock_initial_configuration.cpp @@ -15,12 +15,13 @@ */ #include #include "boot_clock_initial_configuration.hpp" -#include "boot_pmc_wrapper.hpp" namespace ams::boot { namespace { + constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400; + /* Convenience definitions. */ constexpr u32 InitialClockOutMask1x = 0x00C4; constexpr u32 InitialClockOutMask6x = 0xC4C4; @@ -30,7 +31,7 @@ namespace ams::boot { void SetInitialClockConfiguration() { /* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */ const u32 mask = hos::GetVersion() >= hos::Version_6_0_0 ? InitialClockOutMask6x : InitialClockOutMask1x; - WritePmcRegister(PmcBase + APBDEV_PMC_CLK_OUT_CNTRL, mask, mask); + dd::ReadModifyWriteIoRegister(PmcBase + APBDEV_PMC_CLK_OUT_CNTRL, mask, mask); } } diff --git a/stratosphere/boot/source/boot_display.cpp b/stratosphere/boot/source/boot_display.cpp index 65068ff89..67cba618c 100644 --- a/stratosphere/boot/source/boot_display.cpp +++ b/stratosphere/boot/source/boot_display.cpp @@ -16,7 +16,6 @@ #include #include "boot_display.hpp" #include "boot_i2c_utils.hpp" -#include "boot_pmc_wrapper.hpp" #include "boot_registers_di.hpp" @@ -25,7 +24,7 @@ namespace ams::boot { /* Display configuration included into anonymous namespace. */ namespace { -#include "boot_display_config.inc" + #include "boot_display_config.inc" } @@ -39,6 +38,8 @@ namespace ams::boot { constexpr size_t FrameBufferHeight = 1280; constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); + constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400; + constexpr uintptr_t Disp1Base = 0x54200000ul; constexpr uintptr_t DsiBase = 0x54300000ul; constexpr uintptr_t ClkRstBase = 0x60006000ul; @@ -68,19 +69,20 @@ namespace ams::boot { /* Types. */ /* Globals. */ - bool g_is_display_intialized = false; - u32 *g_frame_buffer = nullptr; - spl::SocType g_soc_type = spl::SocType_Erista; - u32 g_lcd_vendor = 0; - Handle g_dc_das_hnd = INVALID_HANDLE; - u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize]; + constinit bool g_is_display_intialized = false; + constinit u32 *g_frame_buffer = nullptr; + constinit spl::SocType g_soc_type = spl::SocType_Erista; + constinit u32 g_lcd_vendor = 0; + constinit Handle g_dc_das_hnd = INVALID_HANDLE; + constinit int g_display_brightness = 100; + constinit u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize]; - uintptr_t g_disp1_regs = 0; - uintptr_t g_dsi_regs = 0; - uintptr_t g_clk_rst_regs = 0; - uintptr_t g_gpio_regs = 0; - uintptr_t g_apb_misc_regs = 0; - uintptr_t g_mipi_cal_regs = 0; + constinit uintptr_t g_disp1_regs = 0; + constinit uintptr_t g_dsi_regs = 0; + constinit uintptr_t g_clk_rst_regs = 0; + constinit uintptr_t g_gpio_regs = 0; + constinit uintptr_t g_apb_misc_regs = 0; + constinit uintptr_t g_mipi_cal_regs = 0; /* Helper functions. */ void InitializeRegisterBaseAddresses() { @@ -119,9 +121,9 @@ namespace ams::boot { } } -#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes)) -#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko)) -#define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, util::size(writes)) + #define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes)) + #define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko)) + #define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, util::size(writes)) void InitializeFrameBuffer() { if (g_frame_buffer != nullptr) { @@ -217,8 +219,8 @@ namespace ams::boot { reg::Write(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); + dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000); + dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000); /* Configure LCD pinmux tristate + passthrough. */ reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); @@ -502,4 +504,8 @@ namespace ams::boot { g_is_display_intialized = false; } + void SetDisplayBrightness(int percentage) { + g_display_brightness = percentage; + } + } diff --git a/stratosphere/boot/source/boot_display.hpp b/stratosphere/boot/source/boot_display.hpp index e046e1ebc..de58eec03 100644 --- a/stratosphere/boot/source/boot_display.hpp +++ b/stratosphere/boot/source/boot_display.hpp @@ -23,4 +23,6 @@ namespace ams::boot { void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img); void FinalizeDisplay(); + void SetDisplayBrightness(int percentage); + } diff --git a/stratosphere/boot/source/boot_pmc_wrapper.cpp b/stratosphere/boot/source/boot_pmc_wrapper.cpp deleted file mode 100644 index 9b2685650..000000000 --- a/stratosphere/boot/source/boot_pmc_wrapper.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include "boot_pmc_wrapper.hpp" - -namespace ams::boot { - - namespace { - - /* Convenience definitions. */ - constexpr dd::PhysicalAddress PmcPhysStart = 0x7000E400; - constexpr dd::PhysicalAddress PmcPhysLast = 0x7000EFFF; - - /* Helpers. */ - bool IsValidPmcAddress(dd::PhysicalAddress phys_addr) { - return util::IsAligned(phys_addr, alignof(u32)) && PmcPhysStart <= phys_addr && phys_addr <= PmcPhysLast; - } - - inline u32 ReadWriteRegisterImpl(dd::PhysicalAddress phys_addr, u32 value, u32 mask) { - u32 out_value; - R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::AtmosphereReadWriteRegister(phys_addr, mask, value, &out_value))); - return out_value; - } - - } - - u32 ReadPmcRegister(dd::PhysicalAddress phys_addr) { - AMS_ABORT_UNLESS(IsValidPmcAddress(phys_addr)); - return ReadWriteRegisterImpl(phys_addr, 0, 0); - } - - void WritePmcRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask) { - AMS_ABORT_UNLESS(IsValidPmcAddress(phys_addr)); - ReadWriteRegisterImpl(phys_addr, value, mask); - } - -} diff --git a/stratosphere/boot/source/boot_pmic_driver.cpp b/stratosphere/boot/source/boot_pmic_driver.cpp index 8dbe39365..877d534de 100644 --- a/stratosphere/boot/source/boot_pmic_driver.cpp +++ b/stratosphere/boot/source/boot_pmic_driver.cpp @@ -20,90 +20,87 @@ namespace ams::boot { void PmicDriver::ShutdownSystem() { - R_ABORT_UNLESS(this->ShutdownSystem(false)); + this->ShutdownSystem(false); } void PmicDriver::RebootSystem() { - R_ABORT_UNLESS(this->ShutdownSystem(true)); + this->ShutdownSystem(true); } Result PmicDriver::GetAcOk(bool *out) { u8 power_status; - R_TRY(this->GetPowerStatus(&power_status)); + R_TRY(this->GetPowerStatus(std::addressof(power_status))); *out = (power_status & 0x02) != 0; return ResultSuccess(); } - Result PmicDriver::GetPowerIntr(u8 *out) { + Result PmicDriver::GetOnOffIrq(u8 *out) { const u8 addr = 0x0B; - return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); + return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)); } Result PmicDriver::GetPowerStatus(u8 *out) { const u8 addr = 0x15; - return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); + return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)); } Result PmicDriver::GetNvErc(u8 *out) { const u8 addr = 0x0C; - return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); + return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)); } Result PmicDriver::GetPowerButtonPressed(bool *out) { - u8 power_intr; - R_TRY(this->GetPowerIntr(&power_intr)); - *out = (power_intr & 0x08) != 0; + u8 on_off_irq; + R_TRY(this->GetOnOffIrq(std::addressof(on_off_irq))); + *out = (on_off_irq & 0x08) != 0; return ResultSuccess(); } - Result PmicDriver::ShutdownSystem(bool reboot) { + void PmicDriver::ShutdownSystem(bool reboot) { const u8 on_off_1_addr = 0x41; const u8 on_off_2_addr = 0x42; /* Get value, set or clear software reset mask. */ u8 on_off_2_val = 0; - R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr))); + R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr))); if (reboot) { on_off_2_val |= 0x80; } else { on_off_2_val &= ~0x80; } - R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr))); + R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr))); /* Get value, set software reset mask. */ u8 on_off_1_val = 0; - R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr))); + R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr))); on_off_1_val |= 0x80; /* Finalize the battery on non-Calcio. */ if (spl::GetHardwareType() != spl::HardwareType::Calcio) { BatteryDriver battery_driver; - this->FinalizeBattery(&battery_driver); + this->FinalizeBattery(battery_driver); } /* Actually write the value to trigger shutdown/reset. */ - R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr))); + R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr))); /* Allow up to 5 seconds for shutdown/reboot to take place. */ - svcSleepThread(5'000'000'000ul); - AMS_ABORT_UNLESS(false); + os::SleepThread(TimeSpan::FromSeconds(5)); + AMS_ABORT("Shutdown failed"); } - void PmicDriver::FinalizeBattery(BatteryDriver *battery_driver) { - /* Set shutdown timer. */ - battery_driver->SetShutdownTimer(); - + void PmicDriver::FinalizeBattery(BatteryDriver &battery_driver) { /* Get whether shutdown is enabled. */ bool shutdown_enabled; - if (R_FAILED(battery_driver->GetShutdownEnabled(&shutdown_enabled))) { + if (R_FAILED(battery_driver.IsI2cShutdownEnabled(std::addressof(shutdown_enabled)))) { return; } /* On Hoag, we don't want to use the desired shutdown value when battery charged. */ bool use_desired_shutdown = true; if (spl::GetHardwareType() == spl::HardwareType::Hoag) { - double battery_charge; - if (R_FAILED(battery_driver->GetSocRep(&battery_charge)) || battery_charge >= 80.0) { + float battery_charge_raw; + if (R_FAILED(battery_driver.GetSocRep(std::addressof(battery_charge_raw))) || battery_charge_raw >= 80.0) { use_desired_shutdown = false; } } @@ -119,7 +116,7 @@ namespace ams::boot { desired_shutdown_enabled &= use_desired_shutdown; if (shutdown_enabled != desired_shutdown_enabled) { - battery_driver->SetShutdownEnabled(desired_shutdown_enabled); + battery_driver.SetI2cShutdownEnabled(desired_shutdown_enabled); } } diff --git a/stratosphere/boot/source/boot_pmic_driver.hpp b/stratosphere/boot/source/boot_pmic_driver.hpp index 256e0ccea..fc17dbaa0 100644 --- a/stratosphere/boot/source/boot_pmic_driver.hpp +++ b/stratosphere/boot/source/boot_pmic_driver.hpp @@ -32,13 +32,13 @@ namespace ams::boot { } private: Result GetPowerStatus(u8 *out); - Result ShutdownSystem(bool reboot); - void FinalizeBattery(BatteryDriver *battery_driver); + void ShutdownSystem(bool reboot); + void FinalizeBattery(BatteryDriver &battery_driver); public: void ShutdownSystem(); void RebootSystem(); Result GetAcOk(bool *out); - Result GetPowerIntr(u8 *out); + Result GetOnOffIrq(u8 *out); Result GetNvErc(u8 *out); Result GetPowerButtonPressed(bool *out); }; diff --git a/stratosphere/boot/source/boot_power_utils.cpp b/stratosphere/boot/source/boot_power_utils.cpp index 3b18807b0..d01342d6c 100644 --- a/stratosphere/boot/source/boot_power_utils.cpp +++ b/stratosphere/boot/source/boot_power_utils.cpp @@ -15,6 +15,7 @@ */ #include #include "boot_power_utils.hpp" +#include "boot_pmic_driver.hpp" #include "fusee-primary_bin.h" namespace ams::boot { @@ -65,7 +66,16 @@ namespace ams::boot { } void RebootSystem() { - DoRebootToPayload(nullptr); + if (spl::GetSocType() == spl::SocType_Erista) { + DoRebootToPayload(nullptr); + } else { + /* On Mariko, we can't reboot to payload, so we should just do a reboot. */ + PmicDriver().RebootSystem(); + } + } + + void ShutdownSystem() { + PmicDriver().ShutdownSystem(); } void SetInitialRebootPayload() { diff --git a/stratosphere/boot/source/boot_splash_screen.cpp b/stratosphere/boot/source/boot_splash_screen.cpp index 01b45aed5..23fa3eb1b 100644 --- a/stratosphere/boot/source/boot_splash_screen.cpp +++ b/stratosphere/boot/source/boot_splash_screen.cpp @@ -29,8 +29,8 @@ namespace ams::boot { } void ShowSplashScreen() { - const u32 boot_reason = GetBootReason(); - if (boot_reason == 1 || boot_reason == 4) { + const auto boot_reason = GetBootReason(); + if (boot_reason == spl::BootReason_AcOk || boot_reason == spl::BootReason_RtcAlarm2) { return; } @@ -38,7 +38,7 @@ namespace ams::boot { { /* Splash screen is shown for 2 seconds. */ ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen); - svcSleepThread(2'000'000'000ul); + os::SleepThread(TimeSpan::FromSeconds(2)); } FinalizeDisplay(); }