Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline dd::PhysicalAddress ClkRstRegistersPhysicalAddress = 0x60006000;
|
||||
constexpr inline size_t ClkRstRegistersSize = 0x1000;
|
||||
|
||||
uintptr_t g_clkrst_registers = dd::QueryIoMapping(ClkRstRegistersPhysicalAddress, ClkRstRegistersSize);
|
||||
|
||||
struct ClkRstDefinition {
|
||||
u32 clk_src_ofs;
|
||||
u32 clk_en_ofs;
|
||||
u32 rst_ofs;
|
||||
u32 clk_en_index;
|
||||
u32 rst_index;
|
||||
u8 clk_src;
|
||||
u8 clk_divisor;
|
||||
};
|
||||
|
||||
constexpr inline const ClkRstDefinition Definitions[] = {
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_ENB_I2C1_INDEX, CLK_RST_CONTROLLER_RST_I2C1_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_ENB_I2C2_INDEX, CLK_RST_CONTROLLER_RST_I2C2_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_ENB_I2C3_INDEX, CLK_RST_CONTROLLER_RST_I2C3_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_ENB_I2C4_INDEX, CLK_RST_CONTROLLER_RST_I2C4_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_ENB_I2C5_INDEX, CLK_RST_CONTROLLER_RST_I2C5_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_ENB_I2C6_INDEX, CLK_RST_CONTROLLER_RST_I2C6_INDEX, 0x00 /* PLLP_OUT0 */, 0x04 },
|
||||
{ CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_ENB_PWM_INDEX, CLK_RST_CONTROLLER_RST_PWM_INDEX, 0x00 /* PLLP_OUT0 */, 0x10 },
|
||||
};
|
||||
|
||||
constexpr inline const struct {
|
||||
const ClkRstDefinition *definition;
|
||||
DeviceCode device_code;
|
||||
pcv::Module pcv_module;
|
||||
} ClkRstDefinitionMap[] = {
|
||||
{ std::addressof(Definitions[0]), i2c::DeviceCode_I2c1, pcv::Module_I2c1 },
|
||||
{ std::addressof(Definitions[1]), i2c::DeviceCode_I2c2, pcv::Module_I2c2 },
|
||||
{ std::addressof(Definitions[2]), i2c::DeviceCode_I2c3, pcv::Module_I2c3 },
|
||||
{ std::addressof(Definitions[3]), i2c::DeviceCode_I2c4, pcv::Module_I2c4 },
|
||||
{ std::addressof(Definitions[4]), i2c::DeviceCode_I2c5, pcv::Module_I2c5 },
|
||||
{ std::addressof(Definitions[5]), i2c::DeviceCode_I2c6, pcv::Module_I2c6 },
|
||||
{ std::addressof(Definitions[6]), pwm::DeviceCode_LcdBacklight, pcv::Module_Pwm },
|
||||
};
|
||||
|
||||
ALWAYS_INLINE const ClkRstDefinition *GetDefinition(DeviceCode device_code) {
|
||||
const ClkRstDefinition *def = nullptr;
|
||||
|
||||
for (const auto &entry : ClkRstDefinitionMap) {
|
||||
if (entry.device_code == device_code) {
|
||||
def = entry.definition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AMS_ABORT_UNLESS(def != nullptr);
|
||||
return def;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const ClkRstDefinition &GetDefinition(pcv::Module module) {
|
||||
const ClkRstDefinition *def = nullptr;
|
||||
|
||||
for (const auto &entry : ClkRstDefinitionMap) {
|
||||
if (entry.pcv_module == module) {
|
||||
def = entry.definition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AMS_ABORT_UNLESS(def != nullptr);
|
||||
return *def;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const ClkRstDefinition &GetDefinition(clkrst::ClkRstSession *session) {
|
||||
const ClkRstDefinition *def = nullptr;
|
||||
|
||||
for (const auto &entry : ClkRstDefinitionMap) {
|
||||
if (session->_session == entry.definition) {
|
||||
def = entry.definition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AMS_ABORT_UNLESS(def != nullptr);
|
||||
return *def;
|
||||
}
|
||||
|
||||
void SetResetEnabled(const ClkRstDefinition &def, bool en) {
|
||||
/* Set or clear reset. */
|
||||
reg::ReadWrite(g_clkrst_registers + def.rst_ofs, (en ? 1u : 0u) << def.rst_index, 1u << def.rst_index);
|
||||
}
|
||||
|
||||
void SetClockEnabled(const ClkRstDefinition &def, bool en) {
|
||||
/* Set or clear reset. */
|
||||
reg::ReadWrite(g_clkrst_registers + def.clk_en_ofs, (en ? 1u : 0u) << def.clk_en_index, 1u << def.clk_en_index);
|
||||
}
|
||||
|
||||
void SetClockRate(const ClkRstDefinition &def, u32 hz) {
|
||||
AMS_UNUSED(hz);
|
||||
|
||||
/* Enable clock. */
|
||||
reg::ReadWrite(g_clkrst_registers + def.clk_en_ofs, 1u << def.clk_en_index, 1u << def.clk_en_index);
|
||||
|
||||
/* Set the clock divisor. */
|
||||
reg::ReadWrite(g_clkrst_registers + def.clk_src_ofs, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_CLK_DIVISOR, def.clk_divisor));
|
||||
|
||||
/* Wait for 2us for clock setting to take. */
|
||||
os::SleepThread(TimeSpan::FromMicroSeconds(2));
|
||||
|
||||
/* Set the clock source. */
|
||||
reg::ReadWrite(g_clkrst_registers + def.clk_src_ofs, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_CLK_SOURCE, def.clk_src));
|
||||
|
||||
/* Wait for 2us for clock setting to take. */
|
||||
os::SleepThread(TimeSpan::FromMicroSeconds(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace clkrst {
|
||||
|
||||
void Initialize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result OpenSession(ClkRstSession *out, DeviceCode device_code) {
|
||||
/* Get the relevant definition. */
|
||||
out->_session = const_cast<ClkRstDefinition *>(GetDefinition(device_code));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void CloseSession(ClkRstSession *session) {
|
||||
/* Clear the session. */
|
||||
session->_session = nullptr;
|
||||
}
|
||||
|
||||
void SetResetAsserted(ClkRstSession *session) {
|
||||
/* Assert reset. */
|
||||
SetResetEnabled(GetDefinition(session), true);
|
||||
}
|
||||
|
||||
void SetResetDeasserted(ClkRstSession *session) {
|
||||
/* Assert reset. */
|
||||
SetResetEnabled(GetDefinition(session), false);
|
||||
}
|
||||
|
||||
void SetClockRate(ClkRstSession *session, u32 hz) {
|
||||
/* Set the clock rate. */
|
||||
SetClockRate(GetDefinition(session), hz);
|
||||
}
|
||||
|
||||
void SetClockDisabled(ClkRstSession *session) {
|
||||
AMS_UNUSED(session);
|
||||
AMS_ABORT("SetClockDisabled not implemented for boot system module");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace pcv {
|
||||
|
||||
void Initialize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result SetClockEnabled(Module module, bool en) {
|
||||
/* Set clock. */
|
||||
SetClockEnabled(GetDefinition(module), en);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetClockRate(Module module, ClockHz hz) {
|
||||
/* Set the clock rate. */
|
||||
SetClockRate(GetDefinition(module), hz);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetReset(Module module, bool en) {
|
||||
/* Set reset. */
|
||||
SetResetEnabled(GetDefinition(module), en);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::regulator {
|
||||
|
||||
void Initialize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result OpenSession(RegulatorSession *out, DeviceCode device_code) {
|
||||
AMS_UNUSED(out, device_code);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void CloseSession(RegulatorSession *session) {
|
||||
AMS_UNUSED(session);
|
||||
}
|
||||
|
||||
bool GetVoltageEnabled(RegulatorSession *session) {
|
||||
AMS_UNUSED(session);
|
||||
return true;
|
||||
}
|
||||
|
||||
Result SetVoltageEnabled(RegulatorSession *session, bool enabled) {
|
||||
AMS_UNUSED(session, enabled);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetVoltageValue(RegulatorSession *session, u32 micro_volts) {
|
||||
AMS_UNUSED(session, micro_volts);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
class BatteryDriver {
|
||||
NON_COPYABLE(BatteryDriver);
|
||||
NON_MOVEABLE(BatteryDriver);
|
||||
private:
|
||||
static constinit inline powctl::Session s_battery_session{powctl::Session::ConstantInitializeTag{}};
|
||||
static constinit inline int s_reference_count{0};
|
||||
public:
|
||||
BatteryDriver() {
|
||||
if ((s_reference_count++) == 0) {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(s_battery_session), powctl::DeviceCode_Max17050, ddsf::AccessMode_ReadWrite));
|
||||
}
|
||||
}
|
||||
|
||||
~BatteryDriver() {
|
||||
if ((--s_reference_count) == 0) {
|
||||
powctl::CloseSession(s_battery_session);
|
||||
}
|
||||
}
|
||||
public:
|
||||
Result IsBatteryRemoved(bool *out) {
|
||||
bool present;
|
||||
R_TRY(powctl::IsBatteryPresent(std::addressof(present), s_battery_session));
|
||||
|
||||
*out = !present;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetChargePercentage(float *out) {
|
||||
R_RETURN(powctl::GetBatteryChargePercentage(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result GetAverageVCell(int *out) {
|
||||
R_RETURN(powctl::GetBatteryAverageVCell(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result GetVoltageFuelGaugePercentage(float *out) {
|
||||
R_RETURN(powctl::GetBatteryVoltageFuelGaugePercentage(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result GetAverageCurrent(int *out) {
|
||||
R_RETURN(powctl::GetBatteryAverageCurrent(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result GetCurrent(int *out) {
|
||||
R_RETURN(powctl::GetBatteryCurrent(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result GetTemperature(float *out) {
|
||||
R_RETURN(powctl::GetBatteryTemperature(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result IsI2cShutdownEnabled(bool *out) {
|
||||
R_RETURN(powctl::IsBatteryI2cShutdownEnabled(out, s_battery_session));
|
||||
}
|
||||
|
||||
Result SetI2cShutdownEnabled(bool en) {
|
||||
R_RETURN(powctl::SetBatteryI2cShutdownEnabled(s_battery_session, en));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_battery_icons.hpp"
|
||||
#include "boot_display.hpp"
|
||||
|
||||
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"
|
||||
|
||||
/* 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) {
|
||||
const size_t fill_x = meter_x + meter_w - fill_w;
|
||||
|
||||
if (fill_x + fill_w > icon_w || meter_y + meter_h > icon_h || fill_x == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 *cur_row = icon + meter_y * icon_w + fill_x;
|
||||
for (size_t y = 0; y < meter_h; y++) {
|
||||
/* Make last column of meter identical to first column of meter. */
|
||||
cur_row[-1] = icon[(meter_y + y) * icon_w + meter_x];
|
||||
|
||||
/* Black out further pixels. */
|
||||
for (size_t x = 0; x < fill_w; x++) {
|
||||
cur_row[x] = 0xFF000000;
|
||||
}
|
||||
cur_row += icon_w;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ShowLowBatteryIcon() {
|
||||
InitializeDisplay();
|
||||
{
|
||||
/* Low battery icon is shown for 5 seconds. */
|
||||
ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
|
||||
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||
}
|
||||
FinalizeDisplay();
|
||||
}
|
||||
|
||||
void StartShowChargingIcon(int battery_percentage, bool wait) {
|
||||
const bool is_red = battery_percentage <= 15;
|
||||
|
||||
const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX;
|
||||
const size_t IconY = is_red ? ChargingRedBatteryY : ChargingBatteryY;
|
||||
const size_t IconW = is_red ? ChargingRedBatteryW : ChargingBatteryW;
|
||||
const size_t IconH = is_red ? ChargingRedBatteryH : ChargingBatteryH;
|
||||
const size_t IconMeterX = is_red ? ChargingRedBatteryMeterX : ChargingBatteryMeterX;
|
||||
const size_t IconMeterY = is_red ? ChargingRedBatteryMeterY : ChargingBatteryMeterY;
|
||||
const size_t IconMeterW = is_red ? ChargingRedBatteryMeterW : ChargingBatteryMeterW;
|
||||
const size_t IconMeterH = is_red ? ChargingRedBatteryMeterH : ChargingBatteryMeterH;
|
||||
const size_t MeterFillW = static_cast<size_t>(IconMeterW * (1.0 - (0.0404 + 0.0096 * static_cast<double>(battery_percentage))) + 0.5);
|
||||
|
||||
/* Create stack buffer, copy icon into it, draw fill meter, draw. */
|
||||
{
|
||||
u32 Icon[IconW * IconH];
|
||||
std::memcpy(Icon, is_red ? ChargingRedBattery : ChargingBattery, sizeof(Icon));
|
||||
FillBatteryMeter(Icon, IconW, IconH, IconMeterX, IconMeterY, IconMeterW, IconMeterH, MeterFillW);
|
||||
|
||||
InitializeDisplay();
|
||||
ShowDisplay(IconX, IconY, IconW, IconH, Icon);
|
||||
}
|
||||
|
||||
/* Wait for 2 seconds if we're supposed to. */
|
||||
if (wait) {
|
||||
os::SleepThread(TimeSpan::FromSeconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
void EndShowChargingIcon() {
|
||||
FinalizeDisplay();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_display.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Battery Display utilities. */
|
||||
void ShowLowBatteryIcon();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_boot_reason.hpp"
|
||||
#include "boot_pmic_driver.hpp"
|
||||
#include "boot_rtc_driver.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Globals. */
|
||||
constinit spl::BootReason g_boot_reason = spl::BootReason_Unknown;
|
||||
constinit bool g_detected_boot_reason = false;
|
||||
|
||||
/* Helpers. */
|
||||
spl::BootReason DetectBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
|
||||
if (power_intr & 0x08) {
|
||||
return spl::BootReason_OnKey;
|
||||
}
|
||||
if (rtc_intr & 0x02) {
|
||||
return spl::BootReason_RtcAlarm1;
|
||||
}
|
||||
if (power_intr & 0x80) {
|
||||
return spl::BootReason_AcOk;
|
||||
}
|
||||
if (rtc_intr & 0x04) {
|
||||
if (nv_erc != 0x80 && !spl::IsRecoveryBoot()) {
|
||||
return spl::BootReason_RtcAlarm2;
|
||||
}
|
||||
}
|
||||
if ((nv_erc & 0x40) && ac_ok) {
|
||||
return spl::BootReason_AcOk;
|
||||
}
|
||||
return spl::BootReason_Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DetectBootReason() {
|
||||
u8 power_intr;
|
||||
u8 rtc_intr;
|
||||
u8 rtc_intr_m;
|
||||
u8 nv_erc;
|
||||
bool ac_ok;
|
||||
|
||||
/* Get values from PMIC. */
|
||||
{
|
||||
PmicDriver pmic_driver;
|
||||
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(std::addressof(rtc_intr)));
|
||||
R_ABORT_UNLESS(rtc_driver.GetRtcIntrM(std::addressof(rtc_intr_m)));
|
||||
}
|
||||
|
||||
/* Set global derived boot reason. */
|
||||
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;
|
||||
}
|
||||
|
||||
spl::BootReason GetBootReason() {
|
||||
AMS_ABORT_UNLESS(g_detected_boot_reason);
|
||||
return g_boot_reason;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Boot Reason utilities. */
|
||||
void DetectBootReason();
|
||||
spl::BootReason GetBootReason();
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_change_voltage.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr u32 Sdmmc3VoltageBit = (1 << 13); /* SDMMC3 */
|
||||
constexpr u32 AudioVoltageBit = (1 << 18); /* AUDIO_HV */
|
||||
constexpr u32 GpioVoltageBit = (1 << 21); /* GPIO */
|
||||
constexpr u32 SpiVoltageBit = (1 << 23); /* SPI_HV */
|
||||
|
||||
constexpr u32 VoltageChangeMask = SpiVoltageBit | GpioVoltageBit | AudioVoltageBit | Sdmmc3VoltageBit;
|
||||
|
||||
constexpr u32 PmcPwrDet = 0x7000E448;
|
||||
constexpr u32 PmcPwrDetVal = 0x7000E4E4;
|
||||
|
||||
}
|
||||
|
||||
void ChangeGpioVoltageTo1_8v() {
|
||||
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
||||
dd::ReadModifyWriteIoRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask);
|
||||
dd::ReadModifyWriteIoRegister(PmcPwrDetVal, 0, VoltageChangeMask);
|
||||
|
||||
/* Sleep for 100 us. */
|
||||
os::SleepThread(TimeSpan::FromMicroSeconds(100));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void ChangeGpioVoltageTo1_8v();;
|
||||
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
enum ChargerStatus {
|
||||
ChargerStatus_Unknown = 0,
|
||||
ChargerStatus_Charging = 1,
|
||||
ChargerStatus_NotCharging = 2,
|
||||
ChargerStatus_ChargeTerminationDone = 3,
|
||||
};
|
||||
|
||||
class ChargerDriver {
|
||||
private:
|
||||
powctl::Session m_charger_session;
|
||||
public:
|
||||
ChargerDriver() : m_charger_session() {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(m_charger_session), powctl::DeviceCode_Bq24193, ddsf::AccessMode_ReadWrite));
|
||||
}
|
||||
|
||||
~ChargerDriver() {
|
||||
powctl::CloseSession(m_charger_session);
|
||||
}
|
||||
|
||||
Result Initialize(bool set_input_current_limit) {
|
||||
/* Configure PINMUX_AUX_CAM_FLASH_EN as tristate + passthrough. */
|
||||
{
|
||||
const uintptr_t apb_regs = dd::QueryIoMapping(0x70000000ul, os::MemoryPageSize);
|
||||
reg::ClearBits(apb_regs + PINMUX_AUX_CAM_FLASH_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
}
|
||||
|
||||
/* Set input current limit to 500 ma. */
|
||||
if (set_input_current_limit) {
|
||||
R_TRY(powctl::SetChargerInputCurrentLimit(m_charger_session, 500));
|
||||
}
|
||||
|
||||
/* Set boost mode current limit to 500 ma. */
|
||||
R_TRY(powctl::SetChargerBoostModeCurrentLimit(m_charger_session, 500));
|
||||
|
||||
/* Disable hi-z mode. */
|
||||
R_TRY(powctl::SetChargerHiZEnabled(m_charger_session, false));
|
||||
|
||||
/* Set configuration to charge battery. */
|
||||
R_TRY(powctl::SetChargerChargerConfiguration(m_charger_session, powctl::ChargerConfiguration_ChargeBattery));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetChargeCurrentState(powctl::ChargeCurrentState *out) {
|
||||
R_RETURN(powctl::GetChargerChargeCurrentState(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetChargeCurrentState(powctl::ChargeCurrentState state) {
|
||||
R_RETURN(powctl::SetChargerChargeCurrentState(m_charger_session, state));
|
||||
}
|
||||
|
||||
Result GetInputCurrentLimit(int *out) {
|
||||
R_RETURN(powctl::GetChargerInputCurrentLimit(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetChargerConfiguration(powctl::ChargerConfiguration cfg) {
|
||||
R_RETURN(powctl::SetChargerChargerConfiguration(m_charger_session, cfg));
|
||||
}
|
||||
|
||||
Result GetFastChargeCurrentLimit(int *out) {
|
||||
R_RETURN(powctl::GetChargerFastChargeCurrentLimit(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetFastChargeCurrentLimit(int limit) {
|
||||
R_RETURN(powctl::SetChargerFastChargeCurrentLimit(m_charger_session, limit));
|
||||
}
|
||||
|
||||
Result GetChargeVoltageLimit(int *out) {
|
||||
R_RETURN(powctl::GetChargerChargeVoltageLimit(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetChargeVoltageLimit(int limit) {
|
||||
R_RETURN(powctl::SetChargerChargeVoltageLimit(m_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), m_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;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetBatteryCompensation(int *out) {
|
||||
R_RETURN(powctl::GetChargerBatteryCompensation(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetBatteryCompensation(int v) {
|
||||
R_RETURN(powctl::SetChargerBatteryCompensation(m_charger_session, v));
|
||||
}
|
||||
|
||||
Result GetVoltageClamp(int *out) {
|
||||
R_RETURN(powctl::GetChargerVoltageClamp(out, m_charger_session));
|
||||
}
|
||||
|
||||
Result SetVoltageClamp(int v) {
|
||||
R_RETURN(powctl::SetChargerVoltageClamp(m_charger_session, v));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,529 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_check_battery.hpp"
|
||||
#include "boot_battery_icons.hpp"
|
||||
#include "boot_boot_reason.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,
|
||||
Shutdown,
|
||||
Reboot,
|
||||
};
|
||||
|
||||
class BatteryChecker {
|
||||
private:
|
||||
boot::ChargerDriver &m_charger_driver;
|
||||
boot::BatteryDriver &m_battery_driver;
|
||||
const powctl::driver::impl::ChargeParameters &m_charge_parameters;
|
||||
powctl::driver::impl::ChargeArbiter m_charge_arbiter;
|
||||
powctl::ChargeCurrentState m_charge_current_state;
|
||||
int m_fast_charge_current_limit;
|
||||
int m_charge_voltage_limit;
|
||||
int m_battery_compensation;
|
||||
int m_voltage_clamp;
|
||||
TimeSpan m_charging_done_interval;
|
||||
bool m_has_start_time;
|
||||
TimeSpan m_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. */
|
||||
m_start_time = os::ConvertToTimeSpan(os::GetSystemTick());
|
||||
m_has_start_time = true;
|
||||
}
|
||||
public:
|
||||
BatteryChecker(boot::ChargerDriver &cd, boot::BatteryDriver &bd, const powctl::driver::impl::ChargeParameters &cp, int cvl) : m_charger_driver(cd), m_battery_driver(bd), m_charge_parameters(cp), m_charge_arbiter(cp.rules, cp.num_rules, cvl), m_charging_done_interval(TimeSpan::FromSeconds(2)), m_has_start_time(false) {
|
||||
/* Get parameters from charger. */
|
||||
if (R_FAILED(m_charger_driver.GetChargeCurrentState(std::addressof(m_charge_current_state)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(m_charger_driver.GetFastChargeCurrentLimit(std::addressof(m_fast_charge_current_limit)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(m_charger_driver.GetChargeVoltageLimit(std::addressof(m_charge_voltage_limit)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(m_charger_driver.GetBatteryCompensation(std::addressof(m_battery_compensation)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(m_charger_driver.GetVoltageClamp(std::addressof(m_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();
|
||||
};
|
||||
|
||||
void BatteryChecker::PrintBatteryStatus(float raw_charge, int voltage, int voltage_threshold) {
|
||||
/* TODO: Print charge/voltage/threshold. */
|
||||
AMS_UNUSED(raw_charge, voltage, voltage_threshold);
|
||||
|
||||
/* Get various battery metrics. */
|
||||
int avg_current, current;
|
||||
float temp, voltage_fuel_gauge_percentage;
|
||||
if (R_FAILED(m_battery_driver.GetAverageCurrent(std::addressof(avg_current)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(m_battery_driver.GetCurrent(std::addressof(current)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(m_battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(m_battery_driver.GetVoltageFuelGaugePercentage(std::addressof(voltage_fuel_gauge_percentage)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Print the things we just got. */
|
||||
AMS_UNUSED(avg_current, current, temp, voltage_fuel_gauge_percentage);
|
||||
}
|
||||
|
||||
bool BatteryChecker::IsChargeDone() {
|
||||
/* Get the charger status. */
|
||||
boot::ChargerStatus charger_status;
|
||||
if (R_FAILED(m_charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
/* 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 m_charge_arbiter.IsBatteryDoneCurrentAcceptable(0);
|
||||
}
|
||||
|
||||
void BatteryChecker::UpdateChargeDoneCurrent() {
|
||||
int done_current = 0;
|
||||
if (m_has_start_time && (os::ConvertToTimeSpan(os::GetSystemTick()) - m_start_time) >= m_charging_done_interval) {
|
||||
/* Get the current. */
|
||||
if (R_FAILED(m_battery_driver.GetCurrent(std::addressof(done_current)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
} else {
|
||||
/* Get the charger status. */
|
||||
boot::ChargerStatus charger_status;
|
||||
if (R_FAILED(m_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update done current. */
|
||||
m_charge_arbiter.SetBatteryDoneCurrent(done_current);
|
||||
}
|
||||
|
||||
void BatteryChecker::UpdateCharger() {
|
||||
/* Get the battery temperature. */
|
||||
float temp;
|
||||
if (R_FAILED(m_battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
/* Update the temperature level. */
|
||||
powctl::BatteryTemperatureLevel temp_level;
|
||||
if (temp < static_cast<float>(m_charge_parameters.temp_min)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::TooLow;
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_low)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::Low;
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_high)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::Medium;
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_max)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::High;
|
||||
} else {
|
||||
temp_level = powctl::BatteryTemperatureLevel::TooHigh;
|
||||
}
|
||||
m_charge_arbiter.SetBatteryTemperatureLevel(temp_level);
|
||||
|
||||
/* Update average voltage. */
|
||||
int avg_v_cell;
|
||||
if (R_FAILED(m_battery_driver.GetAverageVCell(std::addressof(avg_v_cell)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_charge_arbiter.SetBatteryAverageVCell(avg_v_cell);
|
||||
|
||||
/* Update voltage fuel gauge percentage. */
|
||||
float vfgp;
|
||||
if (R_FAILED(m_battery_driver.GetVoltageFuelGaugePercentage(std::addressof(vfgp)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_charge_arbiter.SetBatteryVoltageFuelGaugePercentage(vfgp);
|
||||
|
||||
/* Update charge done current. */
|
||||
this->UpdateChargeDoneCurrent();
|
||||
|
||||
/* Update arbiter power state. */
|
||||
m_charge_arbiter.SetPowerState(powctl::PowerState::ShutdownChargeMain);
|
||||
|
||||
/* Apply the newly selected rule. */
|
||||
this->ApplyArbiterRule();
|
||||
}
|
||||
|
||||
void BatteryChecker::ApplyArbiterRule() {
|
||||
/* Get the selected rule. */
|
||||
const auto *rule = m_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 = m_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(m_charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_NotCharging))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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 = m_fast_charge_current_limit;
|
||||
if (rule_fast_charge_current_limit < cur_fast_charge_current_limit) {
|
||||
if (R_FAILED(m_charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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, m_charge_arbiter.GetChargeVoltageLimit());
|
||||
const auto cur_charge_voltage_limit = m_charge_voltage_limit;
|
||||
if (rule_charge_voltage_limit < cur_charge_voltage_limit) {
|
||||
if (R_FAILED(m_charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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 = m_battery_compensation;
|
||||
if (rule_battery_compensation < cur_battery_compensation) {
|
||||
if (R_FAILED(m_charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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 = m_voltage_clamp;
|
||||
if (rule_voltage_clamp < cur_voltage_clamp) {
|
||||
if (R_FAILED(m_charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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(m_charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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(m_charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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(m_charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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(m_charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_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(m_charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_Charging))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
m_charge_current_state = powctl::ChargeCurrentState_Charging;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
boot::EndShowChargingIcon();
|
||||
is_showing_charging_icon = false;
|
||||
}
|
||||
};
|
||||
|
||||
/* Show the charging display, if we should. */
|
||||
if (show_charging_display) {
|
||||
/* Get the raw battery charge. */
|
||||
float raw_battery_charge;
|
||||
if (R_FAILED(m_battery_driver.GetChargePercentage(std::addressof(raw_battery_charge)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
/* Get the raw battery charge. */
|
||||
float raw_battery_charge;
|
||||
if (R_FAILED(m_battery_driver.GetChargePercentage(std::addressof(raw_battery_charge)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
/* Get the average vcell. */
|
||||
int battery_voltage;
|
||||
if (R_FAILED(m_battery_driver.GetAverageVCell(std::addressof(battery_voltage)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
/* Get whether we're connected to charger. */
|
||||
bool ac_ok;
|
||||
if (R_FAILED((boot::PmicDriver().GetAcOk(std::addressof(ac_ok))))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
/* Decide on a battery voltage threshold. */
|
||||
const auto battery_voltage_threshold = ac_ok ? BatteryVoltageThresholdConnected : BatteryVoltageThresholdDisconnected;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 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;
|
||||
}
|
||||
|
||||
/* Wait a bit before checking again. */
|
||||
constexpr auto BatteryChargeCheckInterval = TimeSpan::FromMilliSeconds(20);
|
||||
os::SleepThread(BatteryChargeCheckInterval);
|
||||
|
||||
/* Update the charger. */
|
||||
this->UpdateCharger();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CheckBatteryCharge() {
|
||||
/* Open a sessions for the charger/battery. */
|
||||
boot::ChargerDriver charger_driver;
|
||||
boot::BatteryDriver battery_driver;
|
||||
|
||||
/* Check if the battery is removed. */
|
||||
{
|
||||
bool removed = false;
|
||||
if (R_FAILED(battery_driver.IsBatteryRemoved(std::addressof(removed))) || removed) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the boot reason. */
|
||||
const auto boot_reason = boot::GetBootReason();
|
||||
|
||||
/* Initialize the charger driver. */
|
||||
if (R_FAILED(charger_driver.Initialize(boot_reason != spl::BootReason_RtcAlarm2)))
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
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_parameters.unknown_x_table == nullptr || charge_parameters.x_table_size == 0) {
|
||||
charge_voltage_limit_mv = charge_parameters.default_charge_voltage_limit;
|
||||
} else {
|
||||
if (R_FAILED(charger_driver.GetChargeVoltageLimit(std::addressof(charge_voltage_limit_mv)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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:
|
||||
boot::ShutdownSystem();
|
||||
break;
|
||||
case CheckBatteryResult::Reboot:
|
||||
boot::RebootSystem();
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void CheckBatteryCharge();
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_check_clock.hpp"
|
||||
#include "boot_power_utils.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr u32 ExpectedPlluDivP = (1 << 16);
|
||||
constexpr u32 ExpectedPlluDivN = (25 << 8);
|
||||
constexpr u32 ExpectedPlluDivM = (2 << 0);
|
||||
constexpr u32 ExpectedPlluVal = (ExpectedPlluDivP | ExpectedPlluDivN | ExpectedPlluDivM);
|
||||
constexpr u32 ExpectedPlluMask = 0x1FFFFF;
|
||||
|
||||
constexpr u32 ExpectedUtmipDivN = (25 << 16);
|
||||
constexpr u32 ExpectedUtmipDivM = (1 << 8);
|
||||
constexpr u32 ExpectedUtmipVal = (ExpectedUtmipDivN | ExpectedUtmipDivM);
|
||||
constexpr u32 ExpectedUtmipMask = 0xFFFF00;
|
||||
|
||||
/* Helpers. */
|
||||
bool IsUsbClockValid() {
|
||||
uintptr_t car_regs = dd::QueryIoMapping(0x60006000ul, os::MemoryPageSize);
|
||||
AMS_ASSERT(car_regs != 0);
|
||||
|
||||
const u32 pllu = reg::Read(car_regs + 0xC0);
|
||||
const u32 utmip = reg::Read(car_regs + 0x480);
|
||||
return ((pllu & ExpectedPlluMask) == ExpectedPlluVal) && ((utmip & ExpectedUtmipMask) == ExpectedUtmipVal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CheckClock() {
|
||||
if (!IsUsbClockValid()) {
|
||||
/* Sleep for 1s, then reboot. */
|
||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||
RebootSystem();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void CheckClock();
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_clock_initial_configuration.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400;
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr u32 InitialClockOutMask1x = 0x00C4;
|
||||
constexpr u32 InitialClockOutMask6x = 0xC4C4;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
dd::ReadModifyWriteIoRegister(PmcBase + APBDEV_PMC_CLK_OUT_CNTRL, mask, mask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void SetInitialClockConfiguration();
|
||||
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_display.hpp"
|
||||
#include "boot_i2c_utils.hpp"
|
||||
|
||||
#include "boot_registers_di.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Display configuration included into anonymous namespace. */
|
||||
namespace {
|
||||
|
||||
#include "boot_display_config.inc"
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Helpful defines. */
|
||||
constexpr size_t DeviceAddressSpaceAlignSize = 4_MB;
|
||||
|
||||
constexpr dd::DeviceVirtualAddress FrameBufferDeviceAddress = DisplayConfigFrameBufferAddress;
|
||||
|
||||
constexpr size_t FrameBufferWidth = 768;
|
||||
constexpr size_t FrameBufferHeight = 1280;
|
||||
constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||
|
||||
constexpr dd::PhysicalAddress PmcBase = 0x7000E400ul;
|
||||
constexpr dd::PhysicalAddress Disp1Base = 0x54200000ul;
|
||||
constexpr dd::PhysicalAddress DsiBase = 0x54300000ul;
|
||||
constexpr dd::PhysicalAddress ClkRstBase = 0x60006000ul;
|
||||
constexpr dd::PhysicalAddress GpioBase = 0x6000D000ul;
|
||||
constexpr dd::PhysicalAddress ApbMiscBase = 0x70000000ul;
|
||||
constexpr dd::PhysicalAddress MipiCalBase = 0x700E3000ul;
|
||||
|
||||
constexpr size_t Disp1Size = 3 * os::MemoryPageSize;
|
||||
constexpr size_t DsiSize = os::MemoryPageSize;
|
||||
constexpr size_t ClkRstSize = os::MemoryPageSize;
|
||||
constexpr size_t GpioSize = os::MemoryPageSize;
|
||||
constexpr size_t ApbMiscSize = os::MemoryPageSize;
|
||||
constexpr size_t MipiCalSize = os::MemoryPageSize;
|
||||
|
||||
constexpr int DsiWaitForCommandMilliSecondsMax = 250;
|
||||
constexpr int DsiWaitForCommandCompletionMilliSeconds = 5;
|
||||
constexpr int DsiWaitForHostControlMilliSecondsMax = 150;
|
||||
|
||||
constexpr size_t GPIO_PORT3_CNF_0 = 0x200;
|
||||
constexpr size_t GPIO_PORT3_OE_0 = 0x210;
|
||||
constexpr size_t GPIO_PORT3_OUT_0 = 0x220;
|
||||
|
||||
constexpr size_t GPIO_PORT6_CNF_1 = 0x504;
|
||||
constexpr size_t GPIO_PORT6_OE_1 = 0x514;
|
||||
constexpr size_t GPIO_PORT6_OUT_1 = 0x524;
|
||||
|
||||
/* Globals. */
|
||||
constinit bool g_is_display_intialized = false;
|
||||
constinit spl::SocType g_soc_type = spl::SocType_Erista;
|
||||
|
||||
constinit u32 g_lcd_vendor = 0;
|
||||
constinit int g_display_brightness = 100;
|
||||
|
||||
constinit dd::DeviceAddressSpaceType g_device_address_space;
|
||||
|
||||
constinit pwm::driver::ChannelSession g_lcd_backlight_session;
|
||||
|
||||
constinit u32 *g_frame_buffer = nullptr;
|
||||
constinit u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize];
|
||||
|
||||
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 InitializeRegisterVirtualAddresses() {
|
||||
g_disp1_regs = dd::QueryIoMapping(Disp1Base, Disp1Size);
|
||||
g_dsi_regs = dd::QueryIoMapping(DsiBase, DsiSize);
|
||||
g_clk_rst_regs = dd::QueryIoMapping(ClkRstBase, ClkRstSize);
|
||||
g_gpio_regs = dd::QueryIoMapping(GpioBase, GpioSize);
|
||||
g_apb_misc_regs = dd::QueryIoMapping(ApbMiscBase, ApbMiscSize);
|
||||
g_mipi_cal_regs = dd::QueryIoMapping(MipiCalBase, MipiCalSize);
|
||||
|
||||
AMS_ABORT_UNLESS(g_disp1_regs != 0);
|
||||
AMS_ABORT_UNLESS(g_dsi_regs != 0);
|
||||
AMS_ABORT_UNLESS(g_clk_rst_regs != 0);
|
||||
AMS_ABORT_UNLESS(g_gpio_regs != 0);
|
||||
AMS_ABORT_UNLESS(g_apb_misc_regs != 0);
|
||||
AMS_ABORT_UNLESS(g_mipi_cal_regs != 0);
|
||||
}
|
||||
|
||||
inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) {
|
||||
switch (g_soc_type) {
|
||||
case spl::SocType_Erista: DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista); break;
|
||||
case spl::SocType_Mariko: DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSleepOrRegisterWrites(uintptr_t base_address, const SleepOrRegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
switch (reg_writes[i].kind) {
|
||||
case SleepOrRegisterWriteKind_Write:
|
||||
reg::Write(base_address + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value);
|
||||
break;
|
||||
case SleepOrRegisterWriteKind_Sleep:
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(reg_writes[i].offset));
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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_SLEEP_OR_REGISTER_WRITES(base_address, writes) DoSleepOrRegisterWrites(base_address, writes, util::size(writes))
|
||||
|
||||
void InitializeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
std::memset(g_frame_buffer, 0x00, FrameBufferSize);
|
||||
dd::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
} else {
|
||||
const uintptr_t frame_buffer_aligned = util::AlignUp(reinterpret_cast<uintptr_t>(g_frame_buffer_storage), DeviceAddressSpaceAlignSize);
|
||||
g_frame_buffer = reinterpret_cast<u32 *>(frame_buffer_aligned);
|
||||
|
||||
std::memset(g_frame_buffer, 0x00, FrameBufferSize);
|
||||
dd::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Create Address Space. */
|
||||
R_ABORT_UNLESS(dd::CreateDeviceAddressSpace(std::addressof(g_device_address_space), 0, (UINT64_C(1) << 32)));
|
||||
|
||||
/* Attach it to the DC. */
|
||||
R_ABORT_UNLESS(dd::AttachDeviceAddressSpace(std::addressof(g_device_address_space), svc::DeviceName_Dc));
|
||||
|
||||
/* Map the framebuffer for the DC as read-only. */
|
||||
R_ABORT_UNLESS(dd::MapDeviceAddressSpaceAligned(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferDeviceAddress, dd::MemoryPermission_ReadOnly));
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
const uintptr_t frame_buffer_aligned = util::AlignUp(reinterpret_cast<uintptr_t>(g_frame_buffer_storage), DeviceAddressSpaceAlignSize);
|
||||
|
||||
/* Unmap the framebuffer from the DC. */
|
||||
dd::UnmapDeviceAddressSpace(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferDeviceAddress);
|
||||
|
||||
/* Detach address space from the DC. */
|
||||
dd::DetachDeviceAddressSpace(std::addressof(g_device_address_space), svc::DeviceName_Dc);
|
||||
|
||||
/* Destroy the address space. */
|
||||
dd::DestroyDeviceAddressSpace(std::addressof(g_device_address_space));
|
||||
|
||||
g_frame_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitDsiTrigger() {
|
||||
os::Tick timeout = os::GetSystemTick() + os::ConvertToTick(TimeSpan::FromMilliSeconds(DsiWaitForCommandMilliSecondsMax));
|
||||
|
||||
while (true) {
|
||||
if (os::GetSystemTick() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(DsiWaitForCommandCompletionMilliSeconds));
|
||||
}
|
||||
|
||||
void WaitDsiHostControl() {
|
||||
os::Tick timeout = os::GetSystemTick() + os::ConvertToTick(TimeSpan::FromMilliSeconds(DsiWaitForHostControlMilliSecondsMax));
|
||||
|
||||
while (true) {
|
||||
if (os::GetSystemTick() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBacklightForVendor2050ForAula(int brightness) {
|
||||
/* Enable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 2);
|
||||
|
||||
/* Configure DSI_LINE_TYPE as FOUR */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 9);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Configure display brightness. */
|
||||
const u32 brightness_val = ((0x7FF * brightness) / 100);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, (brightness_val & 0x700) | ((brightness_val & 0xFF) << 16) | 0x51);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Set client sync point block reset. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 1);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(300));
|
||||
|
||||
/* Clear client sync point block resest. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 0);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(300));
|
||||
|
||||
/* Clear DSI_LINE_TYPE config. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
|
||||
|
||||
/* Disable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 0);
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
}
|
||||
|
||||
void EnableBacklightForGeneric(int brightness) {
|
||||
pwm::driver::SetScale(g_lcd_backlight_session, static_cast<double>(brightness));
|
||||
pwm::driver::SetEnabled(g_lcd_backlight_session, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDisplay() {
|
||||
/* Setup globals. */
|
||||
InitializeRegisterVirtualAddresses();
|
||||
g_soc_type = spl::GetSocType();
|
||||
InitializeFrameBuffer();
|
||||
|
||||
/* Get the hardware type. */
|
||||
const auto hw_type = spl::GetHardwareType();
|
||||
|
||||
/* Turn on DSI/voltage rail. */
|
||||
{
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(i2c_session), i2c::DeviceCode_Max77620Pmic));
|
||||
|
||||
if (g_soc_type == spl::SocType_Mariko) {
|
||||
WriteI2cRegister(i2c_session, 0x18, 0x3A);
|
||||
WriteI2cRegister(i2c_session, 0x1F, 0x71);
|
||||
}
|
||||
WriteI2cRegister(i2c_session, 0x23, 0xD0);
|
||||
|
||||
i2c::driver::CloseSession(i2c_session);
|
||||
}
|
||||
|
||||
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_SET_SET_CLK_ENB_UART_FST_MIPI_CAL, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_SRC, PLLP_OUT3));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DSIA_LP, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_SRC, PLLP_OUT0));
|
||||
|
||||
/* Set IO_DPD_REQ to DPD_OFF. */
|
||||
dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, reg::Encode(PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_OFF)));
|
||||
dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, reg::Encode(PMC_REG_BITS_ENUM(IO_DPD2_REQ_CODE, DPD_OFF)));
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
|
||||
if (hw_type == spl::HardwareType::Aula) {
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4);
|
||||
} else {
|
||||
/* Configure LCD power, VDD. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
}
|
||||
|
||||
/* Configure display interface and display. */
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0);
|
||||
if (g_soc_type == spl::SocType_Mariko) {
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0);
|
||||
reg::Write(g_apb_misc_regs + APB_MISC_GP_DSI_PAD_CONTROL, 0);
|
||||
}
|
||||
|
||||
/* Execute configs. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
|
||||
/* Enable backlight reset. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(60));
|
||||
|
||||
if (hw_type == spl::HardwareType::Aula) {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x40103);
|
||||
} else {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204);
|
||||
}
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
|
||||
WaitDsiHostControl();
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
|
||||
/* Parse LCD vendor. */
|
||||
{
|
||||
u32 host_response[3];
|
||||
for (size_t i = 0; i < util::size(host_response); i++) {
|
||||
host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA);
|
||||
}
|
||||
|
||||
/* The last word from host response is:
|
||||
Bits 0-7: FAB
|
||||
Bits 8-15: REV
|
||||
Bits 16-23: Minor REV
|
||||
*/
|
||||
if ((host_response[2] & 0xFF) == 0x10) {
|
||||
g_lcd_vendor = 0;
|
||||
} else {
|
||||
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
|
||||
}
|
||||
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
|
||||
}
|
||||
|
||||
/* LCD vendor specific configuration. */
|
||||
if (g_lcd_vendor != 0x2050) {
|
||||
/* Configure LCD backlight to use PWM. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x1);
|
||||
reg::Write(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, PINMUX_REG_BITS_ENUM(AUX_LCD_BL_PWM_PM, PWM0),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN));
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
R_ABORT_UNLESS(pwm::driver::OpenSession(std::addressof(g_lcd_backlight_session), pwm::DeviceCode_LcdBacklight));
|
||||
pwm::driver::SetPeriod(g_lcd_backlight_session, TimeSpan::FromNanoSeconds(33898));
|
||||
|
||||
switch (g_lcd_vendor) {
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificInit01);
|
||||
break;
|
||||
case 0xF20: /* Innolux first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(180));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0xF30: /* AUO first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(180));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x1020: /* Innolux second revision screen. */
|
||||
case 0x1030: /* AUO second revision screen. */
|
||||
case 0x1040: /* Unknown second revision screen. */
|
||||
default:
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(120));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* LCD vendor 0x2050, unknown Aula (OLED) screen. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(180));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xA015);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x205315);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x51);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
}
|
||||
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(20));
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09);
|
||||
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4));
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
|
||||
/* Configure MIPI CAL. */
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
if (g_soc_type == spl::SocType_Mariko) {
|
||||
/* On Mariko the above configurations are executed twice, for some reason. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
}
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
|
||||
/* Write DISP1, FrameBuffer config. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer);
|
||||
if (g_lcd_vendor != 0x2050) {
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(35));
|
||||
}
|
||||
g_is_display_intialized = true;
|
||||
}
|
||||
|
||||
void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img) {
|
||||
if (!g_is_display_intialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Draw the image to the screen. */
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
{
|
||||
for (size_t cur_y = 0; cur_y < height; cur_y++) {
|
||||
for (size_t cur_x = 0; cur_x < width; cur_x++) {
|
||||
g_frame_buffer[(FrameBufferHeight - (x + cur_x)) * FrameBufferWidth + y + cur_y] = img[cur_y * width + cur_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
dd::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Enable backlight. */
|
||||
if (g_lcd_vendor == 0x2050) {
|
||||
EnableBacklightForVendor2050ForAula(g_display_brightness);
|
||||
} else {
|
||||
EnableBacklightForGeneric(g_display_brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeDisplay() {
|
||||
if (!g_is_display_intialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable backlight. */
|
||||
if (g_lcd_vendor == 0x2050) {
|
||||
EnableBacklightForVendor2050ForAula(0);
|
||||
} else {
|
||||
pwm::driver::SetEnabled(g_lcd_backlight_session, false);
|
||||
pwm::driver::CloseSession(g_lcd_backlight_session);
|
||||
}
|
||||
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DSI_WR_DATA, 0x2805);
|
||||
|
||||
/* Nintendo waits 5 frames before continuing. */
|
||||
{
|
||||
const uintptr_t host1x_vaddr = dd::GetIoMapping(0x500030A4, 4);
|
||||
const u32 start_val = reg::Read(host1x_vaddr);
|
||||
while (reg::Read(host1x_vaddr) < start_val + 5) {
|
||||
/* spinlock here. */
|
||||
}
|
||||
}
|
||||
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_STATE_ACCESS, (READ_MUX | WRITE_MUX));
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
|
||||
|
||||
DO_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01Fini01);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(40));
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Fini01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Fini02);
|
||||
|
||||
if (g_lcd_vendor != 0x2050) {
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
}
|
||||
|
||||
/* Vendor specific shutdown. */
|
||||
switch (g_lcd_vendor) {
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificFini01);
|
||||
break;
|
||||
case 0xF30: /* AUO first revision screens. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigAuoRev1SpecificFini01);
|
||||
break;
|
||||
case 0x1020: /* Innolux second revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x115631);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
break;
|
||||
case 0x1030: /* AUO second revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x114D31);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
break;
|
||||
case 0x1040: /* Unknown second revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x731348B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71243209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x4C31);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(5));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1005);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
os::SleepThread(g_lcd_vendor == 0x2050 ? TimeSpan::FromMilliSeconds(120) : TimeSpan::FromMilliSeconds(50));
|
||||
|
||||
/* Disable backlight RST/Voltage. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
if (g_lcd_vendor == 0x2050) {
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(30));
|
||||
} else {
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(10));
|
||||
}
|
||||
|
||||
/* Cut clock to DSI. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_PAD_CONTROL_0, (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF)));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0);
|
||||
|
||||
/* Unmap framebuffer from DC virtual address space. */
|
||||
FinalizeFrameBuffer();
|
||||
g_is_display_intialized = false;
|
||||
}
|
||||
|
||||
void SetDisplayBrightness(int percentage) {
|
||||
g_display_brightness = percentage;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Splash Screen/Display utilities. */
|
||||
void InitializeDisplay();
|
||||
void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img);
|
||||
void FinalizeDisplay();
|
||||
|
||||
void SetDisplayBrightness(int percentage);
|
||||
|
||||
}
|
||||
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct RegisterWrite {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum SleepOrRegisterWriteKind : u16 {
|
||||
SleepOrRegisterWriteKind_Write = 0,
|
||||
SleepOrRegisterWriteKind_Sleep = 1,
|
||||
};
|
||||
|
||||
struct SleepOrRegisterWrite {
|
||||
SleepOrRegisterWriteKind kind;
|
||||
u16 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Erista[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_REG_ACT_CONTROL, 0x54},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DC_MCCIF_FIFOCTRL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x0},
|
||||
{sizeof(u32) * DSI_INT_ENABLE, 0x0},
|
||||
{sizeof(u32) * DSI_INT_STATUS, 0x0},
|
||||
{sizeof(u32) * DSI_INT_MASK, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Erista[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Mariko[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init03[] = {
|
||||
{sizeof(u32) * DSI_DCS_CMDS, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0},
|
||||
{sizeof(u32) * DSI_CONTROL, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Erista[] = {
|
||||
/* No register writes. */
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init05[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_CD, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 0x18},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_0_1, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_2_3, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_4_5, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_6_7, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init06[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init07[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingErista[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingMariko[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 180, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Erista[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init08[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDsi01Init09[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_2, 0x30172},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_BTA_TIMING, 0x190A14},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TO_TALLY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_0_LO, 0x40000208},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_2_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_4_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_1_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_0_1, 0xCE0000},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_2_3, 0x87001A2},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_4_5, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_6_7, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_HOST_CONTROL, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init10[] = {
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 6},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Erista[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal01[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Erista[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Mariko[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Erista[] = {
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Mariko[] = {
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006},
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal04[] = {
|
||||
{MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc02[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
/* Set Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_TIMING_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1.
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SYNC_WIDTH, 0x10048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_BACK_PORCH, 0x90048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_ACTIVE, 0x50002D0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
/* End of Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_ENABLE(1), 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
|
||||
};
|
||||
|
||||
constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000;
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigFrameBuffer[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_POSITION, 0}, //(0,0)
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_H_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_V_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_BUFFER_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDc01Fini01[] = {
|
||||
{sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{sizeof(u32) * DC_CMD_INT_MASK, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_INT_ENABLE, 0},
|
||||
{sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini01[] = {
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini02[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2139},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x4F0F41B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF179A433},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2D81},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigAuoRev1SpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D6},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x711148B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x71143209},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x114D31},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 5, 0},
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_driver_management.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void InitializeGpioDriverLibrary() {
|
||||
/* Initialize the gpio client library with the server manager object. */
|
||||
gpio::InitializeWith(gpio::server::GetServiceObject());
|
||||
|
||||
/* Initialize the board driver without enabling interrupt handlers. */
|
||||
gpio::driver::board::Initialize(false);
|
||||
|
||||
/* Initialize the driver library. */
|
||||
gpio::driver::Initialize();
|
||||
}
|
||||
|
||||
void InitializeI2cDriverLibrary() {
|
||||
/* Initialize the i2c client library with the server manager object. */
|
||||
i2c::InitializeWith(i2c::server::GetServiceObject(), i2c::server::GetServiceObjectPowerBus());
|
||||
|
||||
/* Initialize the board driver. */
|
||||
i2c::driver::board::Initialize();
|
||||
|
||||
/* Initialize the driver library. */
|
||||
i2c::driver::Initialize();
|
||||
|
||||
/* Initialize the pwm client library with the server manager object. */
|
||||
pwm::InitializeWith(pwm::server::GetServiceObject());
|
||||
|
||||
/* Initialize the pwm board driver. */
|
||||
pwm::driver::board::Initialize();
|
||||
|
||||
/* Initialize the pwm driver library. */
|
||||
pwm::driver::Initialize();
|
||||
}
|
||||
|
||||
void FinalizeGpioDriverLibrary() {
|
||||
/* Finalize the gpio client library. */
|
||||
gpio::Finalize();
|
||||
}
|
||||
|
||||
void FinalizeI2cDriverLibrary() {
|
||||
/* Finalize the i2c driver library. */
|
||||
i2c::driver::Finalize();
|
||||
|
||||
/* Finalize the i2c client library. */
|
||||
i2c::Finalize();
|
||||
|
||||
/* NOTE: Unknown finalize function is called here by Nintendo. */
|
||||
|
||||
/* Finalize the pwm client library. */
|
||||
pwm::Finalize();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void InitializeGpioDriverLibrary();
|
||||
void InitializeI2cDriverLibrary();
|
||||
void FinalizeGpioDriverLibrary();
|
||||
void FinalizeI2cDriverLibrary();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_fan_enable.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void SetFanPowerEnabled() {
|
||||
if (spl::GetHardwareType() == spl::HardwareType::Copper) {
|
||||
/* TODO */
|
||||
/* boot::gpio::Configure(GpioPadName_FanEnable); */
|
||||
/* boot::gpio::SetDirection(GpioPadName_FanEnable, GpioDirection_Output); */
|
||||
/* boot::gpio::SetValue(GpioPadName_FanEnable, GpioValue_High); */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void SetFanPowerEnabled();
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_i2c_utils.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename F>
|
||||
constexpr Result RetryUntilSuccess(F f) {
|
||||
constexpr auto Timeout = TimeSpan::FromSeconds(10);
|
||||
constexpr auto RetryInterval = TimeSpan::FromMilliSeconds(20);
|
||||
|
||||
TimeSpan cur_time = TimeSpan(0);
|
||||
while (true) {
|
||||
const auto retry_result = f();
|
||||
R_SUCCEED_IF(R_SUCCEEDED(retry_result));
|
||||
|
||||
cur_time += RetryInterval;
|
||||
R_UNLESS(cur_time < Timeout, retry_result);
|
||||
|
||||
os::SleepThread(RetryInterval);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result ReadI2cRegister(i2c::driver::I2cSession &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) {
|
||||
AMS_ABORT_UNLESS(dst != nullptr && dst_size > 0);
|
||||
AMS_ABORT_UNLESS(cmd != nullptr && cmd_size > 0);
|
||||
|
||||
u8 cmd_list[i2c::CommandListLengthMax];
|
||||
i2c::CommandListFormatter formatter(cmd_list, sizeof(cmd_list));
|
||||
|
||||
R_ABORT_UNLESS(formatter.EnqueueSendCommand(i2c::TransactionOption_StartCondition, cmd, cmd_size));
|
||||
R_ABORT_UNLESS(formatter.EnqueueReceiveCommand(static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition), dst_size));
|
||||
|
||||
R_RETURN(RetryUntilSuccess([&]() { R_RETURN(i2c::driver::ExecuteCommandList(dst, dst_size, session, cmd_list, formatter.GetCurrentLength())); }));
|
||||
}
|
||||
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) {
|
||||
AMS_ABORT_UNLESS(src != nullptr && src_size > 0);
|
||||
AMS_ABORT_UNLESS(cmd != nullptr && cmd_size > 0);
|
||||
|
||||
u8 cmd_list[0x20];
|
||||
|
||||
/* N doesn't use a CommandListFormatter here... */
|
||||
std::memcpy(cmd_list + 0, cmd, cmd_size);
|
||||
std::memcpy(cmd_list + cmd_size, src, src_size);
|
||||
|
||||
R_RETURN(RetryUntilSuccess([&]() { R_RETURN(i2c::driver::Send(session, cmd_list, src_size + cmd_size, static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition))); }));
|
||||
}
|
||||
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 address, const u8 value) {
|
||||
R_RETURN(WriteI2cRegister(session, std::addressof(value), sizeof(value), &address, sizeof(address)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* I2C Utilities. */
|
||||
Result ReadI2cRegister(i2c::driver::I2cSession &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 address, const u8 value);
|
||||
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_boot_reason.hpp"
|
||||
#include "boot_change_voltage.hpp"
|
||||
#include "boot_check_battery.hpp"
|
||||
#include "boot_check_clock.hpp"
|
||||
#include "boot_clock_initial_configuration.hpp"
|
||||
#include "boot_driver_management.hpp"
|
||||
#include "boot_fan_enable.hpp"
|
||||
#include "boot_pinmux_initial_configuration.hpp"
|
||||
#include "boot_repair_boot_images.hpp"
|
||||
#include "boot_splash_screen.hpp"
|
||||
#include "boot_power_utils.hpp"
|
||||
|
||||
namespace ams {
|
||||
|
||||
namespace boot {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit u8 g_exp_heap_memory[20_KB];
|
||||
constinit u8 g_unit_heap_memory[5_KB];
|
||||
constinit lmem::HeapHandle g_exp_heap_handle;
|
||||
constinit lmem::HeapHandle g_unit_heap_handle;
|
||||
|
||||
constinit sf::ExpHeapMemoryResource g_exp_heap_memory_resource;
|
||||
constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource;
|
||||
|
||||
void *Allocate(size_t size) {
|
||||
void *mem = lmem::AllocateFromExpHeap(g_exp_heap_handle, size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void Deallocate(void *p, size_t size) {
|
||||
AMS_UNUSED(size);
|
||||
lmem::FreeToExpHeap(g_exp_heap_handle, p);
|
||||
}
|
||||
|
||||
void InitializeHeaps() {
|
||||
/* Create the heaps. */
|
||||
g_exp_heap_handle = lmem::CreateExpHeap(g_exp_heap_memory, sizeof(g_exp_heap_memory), lmem::CreateOption_ThreadSafe);
|
||||
g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe);
|
||||
|
||||
/* Attach the memory resources. */
|
||||
g_exp_heap_memory_resource.Attach(g_exp_heap_handle);
|
||||
g_unit_heap_memory_resource.Attach(g_unit_heap_handle);
|
||||
|
||||
/* Register with ddsf. */
|
||||
ddsf::SetMemoryResource(std::addressof(g_exp_heap_memory_resource));
|
||||
ddsf::SetDeviceCodeEntryHolderMemoryResource(std::addressof(g_unit_heap_memory_resource));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace hos {
|
||||
|
||||
void SetNonApproximateVersionInternal();
|
||||
|
||||
}
|
||||
|
||||
namespace init {
|
||||
|
||||
void InitializeSystemModule() {
|
||||
/* Initialize heaps. */
|
||||
boot::InitializeHeaps();
|
||||
|
||||
/* Connect to sm. */
|
||||
R_ABORT_UNLESS(sm::Initialize());
|
||||
|
||||
/* Initialize fs. */
|
||||
fs::InitializeForSystem();
|
||||
fs::SetAllocator(boot::Allocate, boot::Deallocate);
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Initialize spl. */
|
||||
spl::Initialize();
|
||||
|
||||
/* Set the true hos version. */
|
||||
hos::SetNonApproximateVersionInternal();
|
||||
|
||||
/* Verify that we can sanely execute. */
|
||||
ams::CheckApiVersion();
|
||||
}
|
||||
|
||||
void FinalizeSystemModule() { /* ... */ }
|
||||
|
||||
void Startup() { /* ... */ }
|
||||
|
||||
}
|
||||
|
||||
void ExceptionHandler(FatalErrorContext *ctx) {
|
||||
/* We're boot sysmodule, so manually reboot to fatal error. */
|
||||
boot::RebootForFatalError(ctx);
|
||||
}
|
||||
|
||||
void Main() {
|
||||
/* Set thread name. */
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(boot, Main));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(boot, Main));
|
||||
|
||||
/* Perform atmosphere-specific init. */
|
||||
ams::InitializeForBoot();
|
||||
|
||||
/* Set the reboot payload with ams.mitm. */
|
||||
boot::SetInitialRebootPayload();
|
||||
|
||||
/* Change voltage from 3.3v to 1.8v for select devices. */
|
||||
boot::ChangeGpioVoltageTo1_8v();
|
||||
|
||||
/* Setup gpio. */
|
||||
gpio::driver::SetInitialGpioConfig();
|
||||
|
||||
/* Initialize the gpio server library. */
|
||||
boot::InitializeGpioDriverLibrary();
|
||||
|
||||
/* Initialize the i2c server library. */
|
||||
boot::InitializeI2cDriverLibrary();
|
||||
|
||||
/* Get the hardware type. */
|
||||
const auto hw_type = spl::GetHardwareType();
|
||||
|
||||
/* Initialize the power control library without interrupt event handling. */
|
||||
if (hw_type != spl::HardwareType::Calcio) {
|
||||
powctl::Initialize(false);
|
||||
}
|
||||
|
||||
/* Check USB PLL/UTMIP clock. */
|
||||
boot::CheckClock();
|
||||
|
||||
/* Talk to PMIC/RTC, set boot reason with SPL. */
|
||||
boot::DetectBootReason();
|
||||
|
||||
/* Display the splash screen and check the battery charge. */
|
||||
if (hw_type != spl::HardwareType::Calcio) {
|
||||
/* Display splash screen for two seconds. */
|
||||
boot::ShowSplashScreen();
|
||||
|
||||
/* Check that the battery has enough to boot. */
|
||||
boot::CheckBatteryCharge();
|
||||
}
|
||||
|
||||
/* Configure pinmux + drive pads. */
|
||||
boot::SetInitialPinmuxConfiguration();
|
||||
|
||||
/* Configure the PMC wake pin settings. */
|
||||
gpio::driver::SetInitialWakePinConfig();
|
||||
|
||||
/* Configure output clock. */
|
||||
if (hw_type != spl::HardwareType::Calcio) {
|
||||
boot::SetInitialClockConfiguration();
|
||||
}
|
||||
|
||||
/* Set Fan enable config (Copper only). */
|
||||
boot::SetFanPowerEnabled();
|
||||
|
||||
/* Repair boot partitions in NAND if needed. */
|
||||
boot::CheckAndRepairBootImages();
|
||||
|
||||
/* Finalize the power control library. */
|
||||
if (hw_type != spl::HardwareType::Calcio) {
|
||||
powctl::Finalize();
|
||||
}
|
||||
|
||||
/* Finalize the i2c server library. */
|
||||
boot::FinalizeI2cDriverLibrary();
|
||||
|
||||
/* Finalize the gpio server library. */
|
||||
boot::FinalizeGpioDriverLibrary();
|
||||
|
||||
/* Tell PM to start boot2. */
|
||||
R_ABORT_UNLESS(pmshellInitialize());
|
||||
R_ABORT_UNLESS(pmshellNotifyBootFinished());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Override operator new. */
|
||||
void *operator new(size_t size) {
|
||||
return ams::boot::Allocate(size);
|
||||
}
|
||||
|
||||
void *operator new(size_t size, const std::nothrow_t &) {
|
||||
return ams::boot::Allocate(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p) {
|
||||
return ams::boot::Deallocate(p, 0);
|
||||
}
|
||||
|
||||
void operator delete(void *p, size_t size) {
|
||||
return ams::boot::Deallocate(p, size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size) {
|
||||
return ams::boot::Allocate(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size, const std::nothrow_t &) {
|
||||
return ams::boot::Allocate(size);
|
||||
}
|
||||
|
||||
void operator delete[](void *p) {
|
||||
return ams::boot::Deallocate(p, 0);
|
||||
}
|
||||
|
||||
void operator delete[](void *p, size_t size) {
|
||||
return ams::boot::Deallocate(p, size);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_pinmux_initial_configuration.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void SetInitialPinmuxConfiguration() {
|
||||
pinmux::driver::Initialize();
|
||||
pinmux::driver::SetInitialConfig();
|
||||
pinmux::driver::SetInitialDrivePadConfig();
|
||||
pinmux::driver::Finalize();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void SetInitialPinmuxConfiguration();
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_i2c_utils.hpp"
|
||||
#include "boot_pmic_driver.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void PmicDriver::ShutdownSystem() {
|
||||
this->ShutdownSystem(false);
|
||||
}
|
||||
|
||||
void PmicDriver::RebootSystem() {
|
||||
this->ShutdownSystem(true);
|
||||
}
|
||||
|
||||
Result PmicDriver::GetAcOk(bool *out) {
|
||||
u8 power_status;
|
||||
R_TRY(this->GetPowerStatus(std::addressof(power_status)));
|
||||
*out = (power_status & 0x02) != 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result PmicDriver::GetOnOffIrq(u8 *out) {
|
||||
const u8 addr = 0x0B;
|
||||
R_RETURN(ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetPowerStatus(u8 *out) {
|
||||
const u8 addr = 0x15;
|
||||
R_RETURN(ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetNvErc(u8 *out) {
|
||||
const u8 addr = 0x0C;
|
||||
R_RETURN(ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr)));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetPowerButtonPressed(bool *out) {
|
||||
u8 on_off_irq;
|
||||
R_TRY(this->GetOnOffIrq(std::addressof(on_off_irq)));
|
||||
*out = (on_off_irq & 0x08) != 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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(m_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(m_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(m_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);
|
||||
}
|
||||
|
||||
/* Actually write the value to trigger shutdown/reset. */
|
||||
R_ABORT_UNLESS(WriteI2cRegister(m_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. */
|
||||
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||
AMS_ABORT("Shutdown failed");
|
||||
}
|
||||
|
||||
void PmicDriver::FinalizeBattery(BatteryDriver &battery_driver) {
|
||||
/* Get whether shutdown is enabled. */
|
||||
bool 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) {
|
||||
float battery_charge_raw;
|
||||
if (R_FAILED(battery_driver.GetChargePercentage(std::addressof(battery_charge_raw))) || battery_charge_raw >= 80.0) {
|
||||
use_desired_shutdown = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ac_ok;
|
||||
bool desired_shutdown_enabled;
|
||||
if (R_FAILED(this->GetAcOk(&ac_ok)) || ac_ok) {
|
||||
desired_shutdown_enabled = false;
|
||||
} else {
|
||||
desired_shutdown_enabled = true;
|
||||
}
|
||||
|
||||
desired_shutdown_enabled &= use_desired_shutdown;
|
||||
|
||||
if (shutdown_enabled != desired_shutdown_enabled) {
|
||||
battery_driver.SetI2cShutdownEnabled(desired_shutdown_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "boot_battery_driver.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Driver object. */
|
||||
class PmicDriver {
|
||||
private:
|
||||
i2c::driver::I2cSession m_i2c_session;
|
||||
public:
|
||||
PmicDriver() {
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(m_i2c_session), i2c::DeviceCode_Max77620Pmic));
|
||||
}
|
||||
|
||||
~PmicDriver() {
|
||||
i2c::driver::CloseSession(m_i2c_session);
|
||||
}
|
||||
private:
|
||||
Result GetPowerStatus(u8 *out);
|
||||
void ShutdownSystem(bool reboot);
|
||||
void FinalizeBattery(BatteryDriver &battery_driver);
|
||||
public:
|
||||
void ShutdownSystem();
|
||||
void RebootSystem();
|
||||
Result GetAcOk(bool *out);
|
||||
Result GetOnOffIrq(u8 *out);
|
||||
Result GetNvErc(u8 *out);
|
||||
Result GetPowerButtonPressed(bool *out);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_power_utils.hpp"
|
||||
#include "boot_pmic_driver.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr uintptr_t IramBase = 0x40000000ull;
|
||||
constexpr uintptr_t IramPayloadBase = 0x40010000ull;
|
||||
constexpr size_t IramSize = 0x40000;
|
||||
constexpr size_t IramPayloadMaxSize = 0x24000;
|
||||
constexpr size_t IramFatalErrorContextOffset = 0x2E000;
|
||||
|
||||
/* Globals. */
|
||||
alignas(os::MemoryPageSize) u8 g_work_page[os::MemoryPageSize];
|
||||
|
||||
constexpr const u8 FuseeBin[] = {
|
||||
#embed <fusee.bin>
|
||||
};
|
||||
|
||||
/* Helpers. */
|
||||
void ClearIram() {
|
||||
/* Make page FFs. */
|
||||
std::memset(g_work_page, 0xFF, sizeof(g_work_page));
|
||||
|
||||
/* Overwrite all of IRAM with FFs. */
|
||||
for (size_t ofs = 0; ofs < IramSize; ofs += sizeof(g_work_page)) {
|
||||
exosphere::CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
}
|
||||
|
||||
void DoRebootToPayload() {
|
||||
/* Ensure clean IRAM state. */
|
||||
ClearIram();
|
||||
|
||||
/* Copy in payload. */
|
||||
for (size_t ofs = 0; ofs < sizeof(FuseeBin); ofs += sizeof(g_work_page)) {
|
||||
std::memcpy(g_work_page, FuseeBin + ofs, std::min(static_cast<size_t>(sizeof(FuseeBin) - ofs), sizeof(g_work_page)));
|
||||
exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
|
||||
exosphere::ForceRebootToIramPayload();
|
||||
}
|
||||
|
||||
void DoRebootToFatalError(const ams::FatalErrorContext *ctx) {
|
||||
/* Ensure clean IRAM state. */
|
||||
ClearIram();
|
||||
|
||||
/* Copy in payload. */
|
||||
for (size_t ofs = 0; ofs < sizeof(FuseeBin); ofs += sizeof(g_work_page)) {
|
||||
std::memcpy(g_work_page, FuseeBin + ofs, std::min(static_cast<size_t>(sizeof(FuseeBin) - ofs), sizeof(g_work_page)));
|
||||
exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
|
||||
|
||||
/* Copy in fatal error context, if relevant. */
|
||||
if (ctx != nullptr) {
|
||||
std::memset(g_work_page, 0xCC, sizeof(g_work_page));
|
||||
std::memcpy(g_work_page, ctx, sizeof(*ctx));
|
||||
exosphere::CopyToIram(IramPayloadBase + IramFatalErrorContextOffset, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
|
||||
exosphere::ForceRebootToFatalError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RebootSystem() {
|
||||
if (spl::GetSocType() == spl::SocType_Erista) {
|
||||
DoRebootToPayload();
|
||||
} else {
|
||||
/* On Mariko, we can't reboot to payload, so we should just do a reboot. */
|
||||
PmicDriver().RebootSystem();
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownSystem() {
|
||||
PmicDriver().ShutdownSystem();
|
||||
}
|
||||
|
||||
void SetInitialRebootPayload() {
|
||||
::ams::SetInitialRebootPayload(FuseeBin, sizeof(FuseeBin));
|
||||
}
|
||||
|
||||
void RebootForFatalError(ams::FatalErrorContext *ctx) {
|
||||
DoRebootToFatalError(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* Power utilities. */
|
||||
void RebootSystem();
|
||||
void ShutdownSystem();
|
||||
|
||||
/* Atmosphere power utilities. */
|
||||
void SetInitialRebootPayload();
|
||||
void RebootForFatalError(ams::FatalErrorContext *ctx);
|
||||
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
|
||||
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
|
||||
#define SYNCPT_CNTRL_NO_STALL (1 << 8)
|
||||
#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
|
||||
|
||||
#define DC_CMD_CONT_SYNCPT_VSYNC 0x28
|
||||
#define SYNCPT_VSYNC_ENABLE (1 << 8)
|
||||
|
||||
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
|
||||
|
||||
#define DC_CMD_DISPLAY_COMMAND 0x32
|
||||
#define DISP_CTRL_MODE_STOP (0 << 5)
|
||||
#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
|
||||
#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
|
||||
#define DISP_CTRL_MODE_MASK (3 << 5)
|
||||
|
||||
#define DC_CMD_DISPLAY_POWER_CONTROL 0x36
|
||||
#define PW0_ENABLE (1 << 0)
|
||||
#define PW1_ENABLE (1 << 2)
|
||||
#define PW2_ENABLE (1 << 4)
|
||||
#define PW3_ENABLE (1 << 6)
|
||||
#define PW4_ENABLE (1 << 8)
|
||||
#define PM0_ENABLE (1 << 16)
|
||||
#define PM1_ENABLE (1 << 18)
|
||||
|
||||
#define DC_CMD_INT_STATUS 0x37
|
||||
#define DC_CMD_INT_MASK 0x38
|
||||
#define DC_CMD_INT_ENABLE 0x39
|
||||
|
||||
#define DC_CMD_STATE_ACCESS 0x40
|
||||
#define READ_MUX (1 << 0)
|
||||
#define WRITE_MUX (1 << 2)
|
||||
|
||||
#define DC_CMD_STATE_CONTROL 0x41
|
||||
#define GENERAL_ACT_REQ (1 << 0)
|
||||
#define WIN_A_ACT_REQ (1 << 1)
|
||||
#define WIN_B_ACT_REQ (1 << 2)
|
||||
#define WIN_C_ACT_REQ (1 << 3)
|
||||
#define CURSOR_ACT_REQ (1 << 7)
|
||||
#define GENERAL_UPDATE (1 << 8)
|
||||
#define WIN_A_UPDATE (1 << 9)
|
||||
#define WIN_B_UPDATE (1 << 10)
|
||||
#define WIN_C_UPDATE (1 << 11)
|
||||
#define CURSOR_UPDATE (1 << 15)
|
||||
#define NC_HOST_TRIG (1 << 24)
|
||||
|
||||
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42
|
||||
#define WINDOW_A_SELECT (1 << 4)
|
||||
#define WINDOW_B_SELECT (1 << 5)
|
||||
#define WINDOW_C_SELECT (1 << 6)
|
||||
|
||||
#define DC_CMD_REG_ACT_CONTROL 0x043
|
||||
|
||||
#define DC_COM_CRC_CONTROL 0x300
|
||||
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
|
||||
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
|
||||
|
||||
#define DC_COM_DSC_TOP_CTL 0x33E
|
||||
|
||||
#define DC_DISP_DISP_WIN_OPTIONS 0x402
|
||||
#define HDMI_ENABLE (1 << 30)
|
||||
#define DSI_ENABLE (1 << 29)
|
||||
#define SOR1_TIMING_CYA (1 << 27)
|
||||
#define SOR1_ENABLE (1 << 26)
|
||||
#define SOR_ENABLE (1 << 25)
|
||||
#define CURSOR_ENABLE (1 << 16)
|
||||
|
||||
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
|
||||
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
|
||||
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
|
||||
#define DC_DISP_REF_TO_SYNC 0x406
|
||||
#define DC_DISP_SYNC_WIDTH 0x407
|
||||
#define DC_DISP_BACK_PORCH 0x408
|
||||
#define DC_DISP_ACTIVE 0x409
|
||||
#define DC_DISP_FRONT_PORCH 0x40A
|
||||
|
||||
#define DC_DISP_DISP_CLOCK_CONTROL 0x42E
|
||||
#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
|
||||
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
|
||||
|
||||
#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F
|
||||
#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
|
||||
#define DISP_DATA_FORMAT_DF2S (4 << 0)
|
||||
#define DISP_DATA_FORMAT_DF3S (5 << 0)
|
||||
#define DISP_DATA_FORMAT_DFSPI (6 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0)
|
||||
#define DISP_ALIGNMENT_MSB (0 << 8)
|
||||
#define DISP_ALIGNMENT_LSB (1 << 8)
|
||||
#define DISP_ORDER_RED_BLUE (0 << 9)
|
||||
#define DISP_ORDER_BLUE_RED (1 << 9)
|
||||
|
||||
#define DC_DISP_DISP_COLOR_CONTROL 0x430
|
||||
#define DITHER_CONTROL_MASK (3 << 8)
|
||||
#define DITHER_CONTROL_DISABLE (0 << 8)
|
||||
#define DITHER_CONTROL_ORDERED (2 << 8)
|
||||
#define DITHER_CONTROL_ERRDIFF (3 << 8)
|
||||
#define BASE_COLOR_SIZE_MASK (0xf << 0)
|
||||
#define BASE_COLOR_SIZE_666 (0 << 0)
|
||||
#define BASE_COLOR_SIZE_111 (1 << 0)
|
||||
#define BASE_COLOR_SIZE_222 (2 << 0)
|
||||
#define BASE_COLOR_SIZE_333 (3 << 0)
|
||||
#define BASE_COLOR_SIZE_444 (4 << 0)
|
||||
#define BASE_COLOR_SIZE_555 (5 << 0)
|
||||
#define BASE_COLOR_SIZE_565 (6 << 0)
|
||||
#define BASE_COLOR_SIZE_332 (7 << 0)
|
||||
#define BASE_COLOR_SIZE_888 (8 << 0)
|
||||
|
||||
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
|
||||
#define SC1_H_QUALIFIER_NONE (1 << 16)
|
||||
#define SC0_H_QUALIFIER_NONE (1 << 0)
|
||||
|
||||
#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
|
||||
#define DE_SELECT_ACTIVE_BLANK (0 << 0)
|
||||
#define DE_SELECT_ACTIVE (1 << 0)
|
||||
#define DE_SELECT_ACTIVE_IS (2 << 0)
|
||||
#define DE_CONTROL_ONECLK (0 << 2)
|
||||
#define DE_CONTROL_NORMAL (1 << 2)
|
||||
#define DE_CONTROL_EARLY_EXT (2 << 2)
|
||||
#define DE_CONTROL_EARLY (3 << 2)
|
||||
#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
|
||||
|
||||
#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
|
||||
#define DC_DISP_SD_BL_PARAMETERS 0x4D7
|
||||
#define DC_DISP_SD_BL_CONTROL 0x4DC
|
||||
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
|
||||
|
||||
#define DC_WIN_CSC_YOF 0x611
|
||||
#define DC_WIN_CSC_KYRGB 0x612
|
||||
#define DC_WIN_CSC_KUR 0x613
|
||||
#define DC_WIN_CSC_KVR 0x614
|
||||
#define DC_WIN_CSC_KUG 0x615
|
||||
#define DC_WIN_CSC_KVG 0x616
|
||||
#define DC_WIN_CSC_KUB 0x617
|
||||
#define DC_WIN_CSC_KVB 0x618
|
||||
#define DC_WIN_AD_WIN_OPTIONS 0xB80
|
||||
#define DC_WIN_BD_WIN_OPTIONS 0xD80
|
||||
#define DC_WIN_CD_WIN_OPTIONS 0xF80
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).
|
||||
#define DC_WIN_WIN_OPTIONS 0x700
|
||||
#define H_DIRECTION (1 << 0)
|
||||
#define V_DIRECTION (1 << 2)
|
||||
#define SCAN_COLUMN (1 << 4)
|
||||
#define COLOR_EXPAND (1 << 6)
|
||||
#define CSC_ENABLE (1 << 18)
|
||||
#define WIN_ENABLE (1 << 30)
|
||||
|
||||
#define DC_WIN_COLOR_DEPTH 0x703
|
||||
#define WIN_COLOR_DEPTH_P1 0x0
|
||||
#define WIN_COLOR_DEPTH_P2 0x1
|
||||
#define WIN_COLOR_DEPTH_P4 0x2
|
||||
#define WIN_COLOR_DEPTH_P8 0x3
|
||||
#define WIN_COLOR_DEPTH_B4G4R4A4 0x4
|
||||
#define WIN_COLOR_DEPTH_B5G5R5A 0x5
|
||||
#define WIN_COLOR_DEPTH_B5G6R5 0x6
|
||||
#define WIN_COLOR_DEPTH_AB5G5R5 0x7
|
||||
#define WIN_COLOR_DEPTH_B8G8R8A8 0xC
|
||||
#define WIN_COLOR_DEPTH_R8G8B8A8 0xD
|
||||
#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE
|
||||
#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF
|
||||
#define WIN_COLOR_DEPTH_YCbCr422 0x10
|
||||
#define WIN_COLOR_DEPTH_YUV422 0x11
|
||||
#define WIN_COLOR_DEPTH_YCbCr420P 0x12
|
||||
#define WIN_COLOR_DEPTH_YUV420P 0x13
|
||||
#define WIN_COLOR_DEPTH_YCbCr422P 0x14
|
||||
#define WIN_COLOR_DEPTH_YUV422P 0x15
|
||||
#define WIN_COLOR_DEPTH_YCbCr422R 0x16
|
||||
#define WIN_COLOR_DEPTH_YUV422R 0x17
|
||||
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18
|
||||
#define WIN_COLOR_DEPTH_YUV422RA 0x19
|
||||
|
||||
#define DC_WIN_BUFFER_CONTROL 0x702
|
||||
#define DC_WIN_POSITION 0x704
|
||||
|
||||
#define DC_WIN_SIZE 0x705
|
||||
#define H_SIZE(x) (((x) & 0x1fff) << 0)
|
||||
#define V_SIZE(x) (((x) & 0x1fff) << 16)
|
||||
|
||||
#define DC_WIN_PRESCALED_SIZE 0x706
|
||||
#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
|
||||
#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16)
|
||||
|
||||
#define DC_WIN_H_INITIAL_DDA 0x707
|
||||
#define DC_WIN_V_INITIAL_DDA 0x708
|
||||
|
||||
#define DC_WIN_DDA_INC 0x709
|
||||
#define H_DDA_INC(x) (((x) & 0xffff) << 0)
|
||||
#define V_DDA_INC(x) (((x) & 0xffff) << 16)
|
||||
|
||||
#define DC_WIN_LINE_STRIDE 0x70A
|
||||
#define LINE_STRIDE(x) (x)
|
||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||
#define DC_WIN_DV_CONTROL 0x70E
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
||||
#define DC_WINBUF_START_ADDR 0x800
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
#define DC_WINBUF_SURFACE_KIND 0x80B
|
||||
#define PITCH (0 << 0)
|
||||
#define TILED (1 << 0)
|
||||
#define BLOCK (2 << 0)
|
||||
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
|
||||
|
||||
/*! Display serial interface registers. */
|
||||
#define _DSIREG(reg) ((reg) * 4)
|
||||
|
||||
#define DSI_INCR_SYNCPT_CNTRL 0x1
|
||||
|
||||
#define DSI_RD_DATA 0x9
|
||||
#define DSI_WR_DATA 0xA
|
||||
|
||||
#define DSI_POWER_CONTROL 0xB
|
||||
#define DSI_POWER_CONTROL_ENABLE 1
|
||||
|
||||
#define DSI_INT_ENABLE 0xC
|
||||
#define DSI_INT_STATUS 0xD
|
||||
#define DSI_INT_MASK 0xE
|
||||
|
||||
#define DSI_HOST_CONTROL 0xF
|
||||
#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21)
|
||||
#define DSI_HOST_CONTROL_CRC_RESET (1 << 20)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12)
|
||||
#define DSI_HOST_CONTROL_RAW (1 << 6)
|
||||
#define DSI_HOST_CONTROL_HS (1 << 5)
|
||||
#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4)
|
||||
#define DSI_HOST_CONTROL_IMM_BTA (1 << 3)
|
||||
#define DSI_HOST_CONTROL_PKT_BTA (1 << 2)
|
||||
#define DSI_HOST_CONTROL_CS (1 << 1)
|
||||
#define DSI_HOST_CONTROL_ECC (1 << 0)
|
||||
|
||||
#define DSI_CONTROL 0x10
|
||||
#define DSI_CONTROL_HS_CLK_CTRL (1 << 20)
|
||||
#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16)
|
||||
#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12)
|
||||
#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8)
|
||||
#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4)
|
||||
#define DSI_CONTROL_DCS_ENABLE (1 << 3)
|
||||
#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2)
|
||||
#define DSI_CONTROL_VIDEO_ENABLE (1 << 1)
|
||||
#define DSI_CONTROL_HOST_ENABLE (1 << 0)
|
||||
|
||||
#define DSI_SOL_DELAY 0x11
|
||||
#define DSI_MAX_THRESHOLD 0x12
|
||||
|
||||
#define DSI_TRIGGER 0x13
|
||||
#define DSI_TRIGGER_HOST (1 << 1)
|
||||
#define DSI_TRIGGER_VIDEO (1 << 0)
|
||||
|
||||
#define DSI_TX_CRC 0x14
|
||||
#define DSI_STATUS 0x15
|
||||
#define DSI_INIT_SEQ_CONTROL 0x1A
|
||||
#define DSI_INIT_SEQ_DATA_0 0x1B
|
||||
#define DSI_INIT_SEQ_DATA_1 0x1C
|
||||
#define DSI_INIT_SEQ_DATA_2 0x1D
|
||||
#define DSI_INIT_SEQ_DATA_3 0x1E
|
||||
#define DSI_PKT_SEQ_0_LO 0x23
|
||||
#define DSI_PKT_SEQ_0_HI 0x24
|
||||
#define DSI_PKT_SEQ_1_LO 0x25
|
||||
#define DSI_PKT_SEQ_1_HI 0x26
|
||||
#define DSI_PKT_SEQ_2_LO 0x27
|
||||
#define DSI_PKT_SEQ_2_HI 0x28
|
||||
#define DSI_PKT_SEQ_3_LO 0x29
|
||||
#define DSI_PKT_SEQ_3_HI 0x2A
|
||||
#define DSI_PKT_SEQ_4_LO 0x2B
|
||||
#define DSI_PKT_SEQ_4_HI 0x2C
|
||||
#define DSI_PKT_SEQ_5_LO 0x2D
|
||||
#define DSI_PKT_SEQ_5_HI 0x2E
|
||||
#define DSI_DCS_CMDS 0x33
|
||||
#define DSI_PKT_LEN_0_1 0x34
|
||||
#define DSI_PKT_LEN_2_3 0x35
|
||||
#define DSI_PKT_LEN_4_5 0x36
|
||||
#define DSI_PKT_LEN_6_7 0x37
|
||||
#define DSI_PHY_TIMING_0 0x3C
|
||||
#define DSI_PHY_TIMING_1 0x3D
|
||||
#define DSI_PHY_TIMING_2 0x3E
|
||||
#define DSI_BTA_TIMING 0x3F
|
||||
|
||||
#define DSI_TIMEOUT_0 0x44
|
||||
#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16)
|
||||
#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0)
|
||||
|
||||
#define DSI_TIMEOUT_1 0x45
|
||||
#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16)
|
||||
#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0)
|
||||
|
||||
#define DSI_TO_TALLY 0x46
|
||||
|
||||
#define DSI_PAD_CONTROL_0 0x4B
|
||||
#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24)
|
||||
#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
#define DSI_PAD_CONTROL_2 0x50
|
||||
|
||||
#define DSI_PAD_CONTROL_3 0x51
|
||||
#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12)
|
||||
#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8)
|
||||
#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4)
|
||||
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_4 0x52
|
||||
#define DSI_PAD_CONTROL_5_MARIKO 0x53
|
||||
#define DSI_PAD_CONTROL_6_MARIKO 0x54
|
||||
#define DSI_PAD_CONTROL_7_MARIKO 0x55
|
||||
#define DSI_INIT_SEQ_DATA_15 0x5F
|
||||
|
||||
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_power_utils.hpp"
|
||||
#include "boot_repair_boot_images.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Globals. */
|
||||
alignas(os::MemoryPageSize) u8 g_boot_image_work_buffer[0x10000];
|
||||
|
||||
}
|
||||
|
||||
void CheckAndRepairBootImages() {
|
||||
const auto boot_image_update_type = updater::GetBootImageUpdateType(spl::GetHardwareType());
|
||||
|
||||
bool repaired_normal, repaired_safe;
|
||||
if (R_SUCCEEDED(updater::VerifyBootImagesAndRepairIfNeeded(&repaired_normal, &repaired_safe, g_boot_image_work_buffer, sizeof(g_boot_image_work_buffer), boot_image_update_type)) && repaired_normal) {
|
||||
/* Nintendo only performs a reboot on successful normal repair. */
|
||||
RebootSystem();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void CheckAndRepairBootImages();
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_rtc_driver.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
Result RtcDriver::ReadRtcRegister(u8 *out, u8 address) {
|
||||
const u8 update_addr = 0x04;
|
||||
const u8 update_val = 0x10;
|
||||
R_TRY(WriteI2cRegister(m_i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr)));
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(16));
|
||||
R_RETURN(ReadI2cRegister(m_i2c_session, out, sizeof(*out), &address, sizeof(address)));
|
||||
}
|
||||
|
||||
Result RtcDriver::GetRtcIntr(u8 *out) {
|
||||
const u8 addr = 0x00;
|
||||
R_RETURN(ReadI2cRegister(m_i2c_session, out, sizeof(*out), &addr, sizeof(addr)));
|
||||
}
|
||||
|
||||
Result RtcDriver::GetRtcIntrM(u8 *out) {
|
||||
const u8 addr = 0x01;
|
||||
R_RETURN(this->ReadRtcRegister(out, addr));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "boot_i2c_utils.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
class RtcDriver {
|
||||
private:
|
||||
i2c::driver::I2cSession m_i2c_session;
|
||||
public:
|
||||
RtcDriver() {
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(m_i2c_session), i2c::DeviceCode_Max77620Rtc));
|
||||
}
|
||||
|
||||
~RtcDriver() {
|
||||
i2c::driver::CloseSession(m_i2c_session);
|
||||
}
|
||||
private:
|
||||
Result ReadRtcRegister(u8 *out, u8 address);
|
||||
public:
|
||||
Result GetRtcIntr(u8 *out);
|
||||
Result GetRtcIntrM(u8 *out);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "boot_boot_reason.hpp"
|
||||
#include "boot_display.hpp"
|
||||
#include "boot_splash_screen.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Include splash screen into anonymous namespace. */
|
||||
/* TODO: Compile-time switch for splash_screen_text.hpp? */
|
||||
#include "boot_splash_screen_notext.inc"
|
||||
|
||||
}
|
||||
|
||||
void ShowSplashScreen() {
|
||||
const auto boot_reason = GetBootReason();
|
||||
if (boot_reason == spl::BootReason_AcOk || boot_reason == spl::BootReason_RtcAlarm2) {
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeDisplay();
|
||||
{
|
||||
/* Splash screen is shown for 2 seconds. */
|
||||
ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen);
|
||||
os::SleepThread(TimeSpan::FromSeconds(2));
|
||||
}
|
||||
FinalizeDisplay();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
void ShowSplashScreen();
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user